---
title: 'Implementing TDD in IntelliSIEM: Handling Edge Cases and Errors'
url: 'https://bsb.perryconsulting.net/blog/strengthening-the-foundation-with-comprehensive-testing-in-intellisiem'
markdown: 'https://bsb.perryconsulting.net/blog/strengthening-the-foundation-with-comprehensive-testing-in-intellisiem.md'
date: '2024-09-28'
description: "Previous entries in this series covered the initial tool setup and testing of the environment, establishing the structure of the project, initial tests, and connecting to APIs. In this third entry, we're going to enhance our testing approach through a Test-Driven Development (TDD) methodology to build a more robust and reliable system. Initially, our tests covered basic scenarios but didn’t fully account for real-world challenges like invalid configurations, API rate limits, and malformed data. We will expand our test cases significantly to address this, focusing on edge cases and error handling. To see this project in its curr"
taxonomy:
  category:
    - projects
  tag:
    - python
    - security
---

# Implementing TDD in IntelliSIEM: Handling Edge Cases and Errors

 28 SEP 2024  [python](https://bsb.perryconsulting.net/blog/tag:python) [security](https://bsb.perryconsulting.net/blog/tag:security)  

  *Previous entries in this series covered the initial tool setup and testing of the environment, establishing the structure of the project, initial tests, and connecting to APIs. In this third entry, we're going to* *enhance our testing approach through a Test-Driven Development (TDD) methodology to build a more robust and reliable system.*

Initially, our tests covered basic scenarios but didn’t fully account for real-world challenges like invalid configurations, API rate limits, and malformed data. We will expand our test cases significantly to address this, focusing on edge cases and error handling.

To see this project in its current state, head over to my repo and check it out: [IntelliSIEM on GitHub](https://github.com/perryconsulting/IntelliSIEM)

---

### **Enhancing Our Test Scenarios**

In our initial design, we tested for success and failure of threat data collection from the APIs, but what about other potential issues? Let's expand out our testing to ensure that we're handling other potential data issues such as an empty or corrupt response. Here's the new `tests/test_data_collection.py`:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> tests/test_data_collection.py</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">pytest</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">data_collection</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">,</span><span class="token"> </span><span class="token">APIError</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_fetch_threat_data_success</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test fetching threat data with valid API keys.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.api_client.APIClient.get_data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">[</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">id</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">test</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">}</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token">    </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">assert</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">len</span><span class="token">(</span><span class="token">threats</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">></span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_fetch_threat_data_failure</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test fetching threat data with invalid API keys.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token">    </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Mock API client responses to raise an error</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.api_client.APIClient.get_data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">side_effect</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API Error</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">    </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Expect the APIError exception to be raised and handle it in the function</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token">    </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">36</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">assert</span><span class="token"> </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">==</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Expecting an empty list as a fallback</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">37</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">38</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_fetch_threat_data_empty_response</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">39</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">40</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test fetching threat data with an empty response.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">41</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">42</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.api_client.APIClient.get_data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">[</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">43</span><span class="token">    </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">44</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">assert</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">len</span><span class="token">(</span><span class="token">threats</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">==</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">0</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Expecting empty list when no data is returned</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">45</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">46</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_fetch_threat_data_corrupt_data</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">47</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">48</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test fetching threat data with corrupt response data.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">49</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">50</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.api_client.APIClient.get_data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">[</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">malformed</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">}</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">51</span><span class="token">    </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">52</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">assert</span><span class="token"> </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">==</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Expecting empty list on data parsing failure</span><span class="token">
</span></span>
```

In the same vein, we also need to make sure we can handle things like a missing or invalid config file, so we'll add a new test file `tests/test_config.py`:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">pytest</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">config</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">load_config</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">error_handling</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">APIError</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_load_config_missing_file</span><span class="token">(</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test loading configuration with a missing file.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">FileNotFoundError</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token">        </span><span class="token">load_config</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">config/non_existent_config.yaml</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_load_config_invalid_format</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test loading configuration file with an invalid format.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">builtins.open</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token">mocker</span><span class="token">.</span><span class="token">mock_open</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">read_data</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">invalid_yaml</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token">        </span><span class="token">load_config</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span>
```

APIs can be unpredictable sometimes. We should also make sure we can handle other potential API issues that come up, like timeouts, rate limiting, and invalid responses, so we'll also add a new `tests/test_api_client.py`:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">pytest</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">requests</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">api_client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">APIClient</span><span class="token">,</span><span class="token"> </span><span class="token">APIError</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_timeout</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of a timeout error.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">side_effect</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">requests</span><span class="token">.</span><span class="token">exceptions</span><span class="token">.</span><span class="token">Timeout</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token">    </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Match a more general pattern, ignoring the specific exception message.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_invalid_response</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of invalid JSON response.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">status_code</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">200</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">json</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">side_effect</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">ValueError</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid response format.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">36</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">37</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">38</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_rate_limit</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">39</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">40</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of rate limiting.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">41</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">42</span><span class="token">    </span><span class="token">mock_response</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">status_code</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">429</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">headers</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Retry-After</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">5</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">43</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mock_response</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">44</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">45</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Rate limit exceeded.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">46</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

### **Time To Retest Our Code**

Now that we've got our shiny new tests in place, it's time to see how well we did.

BASH

```
<span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">pytest</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">/tests</span><span class="token">
</span></span>
```

I hope you like the color red because there's quite a bit of it. The good news is that because we're letting our tests determine how we implement, all these error messages will point us in exactly the right direction to help ensure our error handling and function implementations are as correct as we can make them.

*Some of you, depending on which version of the project you're on, may notice an error relating to the failure to load APIError from the config.py file. Don't worry; we'll fix that below as we work through the other issues.*

*Note: the snipped output below does not reflect the actual color you may see in your terminal. My preferred dev environment generally uses the various JetBrains tools on Fedora, so my error output is bright red. The plugin I use for this site uses the default VSCode color scheme.*

BASH

```
<span class="line"><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">=</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">short</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">test</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">summary</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">info</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">============================================================================================================================</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">FAILED</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">tests/test_api_client.py::test_api_client_timeout</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">-</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">AssertionError:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Regex</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">pattern</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">did</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">not</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">match.</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">FAILED</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">tests/test_api_client.py::test_api_client_invalid_response</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">-</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">ValueError</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">FAILED</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">tests/test_api_client.py::test_api_client_rate_limit</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">-</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Failed:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">DID</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">NOT</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">RAISE</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492"><</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">class</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.error_handling.APIError</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">></span><span class="token">
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">FAILED</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">tests/test_config.py::test_load_config_invalid_format</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">-</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Failed:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">DID</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">NOT</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">RAISE</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492"><</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">class</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.error_handling.APIError</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">></span><span class="token">
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">FAILED</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">tests/test_data_collection.py::test_fetch_threat_data_corrupt_data</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">-</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">AssertionError:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">assert</span><span class="token"> [</span><span class="token">{</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">'</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">malformed</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">'</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">.</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">m</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">e</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">d</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">'</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">: </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">'</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">data</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">'</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">}] == []
</span></span><span class="line"><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">========================================================================================================================= 5 failed, 4 passed in 0.33s ==========================================================================================================================
</span></span>
```

Remember, we implemented the tests before we actually implemented the code to handle those situations! Let's walk through each of these in order and fix them. Note that I will only provide the changes to implement for each file until all changes have been implemented, then I will show the full final version.

### Failure 1: test\_api\_client\_timeout - AssertionError

The regex pattern for the raised `APIError` did not match the actual error message. The simple fact is, we haven't implemented a specific error handler for this yet. Here's the specific test we're looking at:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_timeout</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of a timeout error.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">side_effect</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">requests</span><span class="token">.</span><span class="token">exceptions</span><span class="token">.</span><span class="token">Timeout</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token">    </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Match a more general pattern, ignoring the specific exception message.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

We need to modify the `src/api_client.py get_data` method to raise a specific error message for a timeout error:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token">requests</span><span class="token">.</span><span class="token">exceptions</span><span class="token">.</span><span class="token">Timeout</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

If we re-run our tests again, there should be one less to worry about.

### **Failure 2: test\_api\_client\_invalid\_response - ValueError**

This test looks for JSON parsing errors, but the current implementation doesn't specifically catch them:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_invalid_response</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of invalid JSON response.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">status_code</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">200</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">json</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">side_effect</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">ValueError</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid response format.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

Still working in `api_client.py`, we should catch this exception and raise an appropriate `APIError`.

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">ValueError</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid JSON response format from API</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid response format.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> New error for invalid JSON responses</span><span class="token">
</span></span>
```

### **Failure 3: test\_api\_client\_rate\_limit - Failed: DID NOT RAISE**

This message is a bit different from the previous two. When our account is rate-limited by the remote service, we should get a specific status code that triggers an error for us to handle. This test case expects an `APIError` to be raised, but the current implementation doesn't specifically handle the `429` status code.

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_api_client_rate_limit</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test API client handling of rate limiting.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token">    </span><span class="token">mock_response</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">mocker</span><span class="token">.</span><span class="token">Mock</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">status_code</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">429</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">headers</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Retry-After</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">5</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">requests.get</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">mock_response</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token">    </span><span class="token">client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://example.com/api</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Authorization</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Bearer token</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Rate limit exceeded.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token">        </span><span class="token">client</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">endpoint</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

Let's go ahead and make sure we handle this case. For now, we want to raise the exception. Later, we may wish to consider refactoring this code to address the situation differently. This is the last error specific to the api\_client.py file, so here's the final code to date:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">requests</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">error_handling</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token">log_error</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">class</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">APIClient</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    A client for interacting with various threat intelligence APIs.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">__init__</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">self</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">base_url</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">headers</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token">        </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        Initialize the API client with the base URL and headers.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :param base_url: (str) The base URL of the API.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :param headers: (dict) Headers required for API requests.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token">        </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">self</span><span class="token">.</span><span class="token">base_url</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">base_url</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token">        </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">self</span><span class="token">.</span><span class="token">headers</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">headers</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">get_data</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">self</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">endpoint</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">params</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">None</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">        </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        Fetch data from the specified endpoint.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">36</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">37</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :param endpoint: (str) The API endpoint to fetch data from.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">38</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :param params: (dict) Optional query parameters.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">39</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :return: (dict) JSON response from the API.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">40</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        :raises APIError: If there is an error with the API request.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">41</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">42</span><span class="token">        </span><span class="token">url</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">self</span><span class="token">.</span><span class="token">base_url</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">/</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">endpoint</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">43</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">try</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">44</span><span class="token">            </span><span class="token">response</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">requests</span><span class="token">.</span><span class="token">get</span><span class="token">(</span><span class="token">url</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">headers</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">self</span><span class="token">.</span><span class="token">headers</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">params</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">params</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">timeout</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">10</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">45</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">if</span><span class="token"> </span><span class="token">response</span><span class="token">.</span><span class="token">status_code</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">==</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">429</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">46</span><span class="token">                </span><span class="token">retry_after</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">response</span><span class="token">.</span><span class="token">headers</span><span class="token">.</span><span class="token">get</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Retry-After</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">unknown time</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">47</span><span class="token">                </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Rate limit exceeded. Retry after: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">retry_after</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">48</span><span class="token">                </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Rate limit exceeded.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">49</span><span class="token">            </span><span class="token">response</span><span class="token">.</span><span class="token">raise_for_status</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">50</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">return</span><span class="token"> </span><span class="token">response</span><span class="token">.</span><span class="token">json</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">51</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token">requests</span><span class="token">.</span><span class="token">exceptions</span><span class="token">.</span><span class="token">Timeout</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">52</span><span class="token">            </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">53</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request timed out</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">54</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token">requests</span><span class="token">.</span><span class="token">exceptions</span><span class="token">.</span><span class="token">RequestException</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">as</span><span class="token"> </span><span class="token">e</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">55</span><span class="token">            </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request failed: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">e</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">56</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">API request failed: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">e</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">57</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">ValueError</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">58</span><span class="token">            </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid JSON response format from API</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">59</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Invalid response format.</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> New error for invalid JSON responses</span><span class="token">
</span></span>
```

### **Failure 4: test\_load\_config\_invalid\_format - Failed: DID NOT RAISE**

The `test_load_config_invalid_format` test case expects an `APIError`, but the current `load_config` function doesn't raise it.

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_load_config_invalid_format</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test loading configuration file with an invalid format.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">builtins.open</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token">mocker</span><span class="token">.</span><span class="token">mock_open</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">read_data</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">invalid_yaml</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token">        </span><span class="token">load_config</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span>
```

Let's go ahead and update `load_config()` to raise `APIError` for parsing issues. Now, is this truly an API error? Nope. Should there be a separate class of errors relating to the application configuration? Probably. We'll add that to our TODO list, and circle back on the next post when we take a careful look at our error handling strategy. For now, this is the only failure related to `config.py`, so here's the current file:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">yaml</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">error_handling</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">log_error</span><span class="token">,</span><span class="token"> </span><span class="token">APIError</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">load_config</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">config_file</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">config/config.yaml</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Load configuration from the specified YAML file.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    :param config_file: (str) The path to the YAML configuration file.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    :return: dict: Configuration data.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    :raises APIError: If there is an error with the configuration file.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">try</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">open</span><span class="token">(</span><span class="token">config_file</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">r</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">as</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">file</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token">            </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">return</span><span class="token"> </span><span class="token">yaml</span><span class="token">.</span><span class="token">safe_load</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">file</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token">yaml</span><span class="token">.</span><span class="token">YAMLError</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">as</span><span class="token"> </span><span class="token">e</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token">        </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">YAML parsing error while loading configuration: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">e</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token">APIError</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Configuration file error: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">e</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">FileNotFoundError</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">        </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Configuration file not found: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">config_file</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">raise</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">FileNotFoundError</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Configuration file not found: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">config_file</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span>
```

Now, interestingly, with this particular case there is also an issue with the test itself where `mocker` isn't providing test data quite correctly. To resolve this, we're also going to update our `test_config.py` file to be more specific with our test:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">pytest</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">config</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">load_config</span><span class="token">,</span><span class="token"> </span><span class="token">APIError</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_load_config_missing_file</span><span class="token">(</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test loading configuration with a missing file.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">FileNotFoundError</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token">        </span><span class="token">load_config</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">config/non_existent_config.yaml</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_load_config_invalid_format</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test loading configuration file with an invalid format.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token">    </span><span class="token">invalid_yaml</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    api_keys:
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">        alien_vault: !!invalid
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">builtins.open</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token">mocker</span><span class="token">.</span><span class="token">mock_open</span><span class="token">(</span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">read_data</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">invalid_yaml</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">with</span><span class="token"> </span><span class="token">pytest</span><span class="token">.</span><span class="token">raises</span><span class="token">(</span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">match</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Configuration file error</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token">        </span><span class="token">load_config</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span>
```

### **Failure 5: test\_fetch\_threat\_data\_corrupt\_data - AssertionError**

OK. Last test failure. In this case, another Assertion Error. The `test_fetch_threat_data_corrupt_data` test case expects an empty list for malformed data, but currently, the function does not filter it:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">test_fetch_threat_data_corrupt_data</span><span class="token">(</span><span class="token" style="color: #0e1116;;--phiki-dark-color: #f0f3f6">mocker</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Test fetching threat data with corrupt response data.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token">    </span><span class="token">mocker</span><span class="token">.</span><span class="token">patch</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">src.api_client.APIClient.get_data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">return_value</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">[</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">malformed</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">data</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">}</span><span class="token">]</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token">    </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">assert</span><span class="token"> </span><span class="token">threats</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">==</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Expecting empty list on data parsing failure</span><span class="token">
</span></span>
```

We need to update the `fetch_threat_data` function to handle malformed data. This is the only edit to `data_collection.py`, so here's the full code:

PYTHON

```
<span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 1</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  IntelliSIEM Copyright 2024, Rob Perry</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 2</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 3</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Licensed under the Apache License, Version 2.0 (the "License");</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 4</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  you may not use this file except in compliance with the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 5</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  You may obtain a copy of the License at</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 6</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 7</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">      http://www.apache.org/licenses/LICENSE-2.0</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 8</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none"> 9</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  Unless required by applicable law or agreed to in writing, software</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">10</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  distributed under the License is distributed on an "AS IS" BASIS,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">11</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">12</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  See the License for the specific language governing permissions and</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">13</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">  limitations under the License.</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">14</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">15</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">api_client</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">APIClient</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">16</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">error_handling</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">APIError</span><span class="token">,</span><span class="token"> </span><span class="token">log_error</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">17</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">from</span><span class="token"> </span><span class="token">src</span><span class="token">.</span><span class="token">config</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">import</span><span class="token"> </span><span class="token">load_config</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">18</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">19</span><span class="token">config</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">load_config</span><span class="token">(</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">20</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">21</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">def</span><span class="token"> </span><span class="token" style="color: #622cbc;;--phiki-dark-color: #dbb7ff">fetch_threat_data</span><span class="token">(</span><span class="token">)</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">22</span><span class="token">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">23</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    Fetch threat data from various sources and return the combined result.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">24</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">25</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    :return: (list) A list of threat intelligence data.
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">26</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">    </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"""</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">27</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">try</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">28</span><span class="token">        </span><span class="token">alien_vault</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://otx.alienvault.com/api/v1</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">29</span><span class="token">                                </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">X-OTX-API-KEY</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token">config</span><span class="token">[</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">api_keys</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">]</span><span class="token">[</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">alien_vault</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">]</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">30</span><span class="token">        </span><span class="token">vt</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">APIClient</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">https://www.virustotal.com/api/v3</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">x-apikey</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token">config</span><span class="token">[</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">api_keys</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">]</span><span class="token">[</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">virus_total</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token">]</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">31</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">32</span><span class="token">        </span><span class="token">alien_vault_data</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">alien_vault</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">indicators/export</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">33</span><span class="token">        </span><span class="token">vt_data</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">vt</span><span class="token">.</span><span class="token">get_data</span><span class="token">(</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">files</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #702c00;;--phiki-dark-color: #ffb757">params</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token">{</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">limit</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">:</span><span class="token"> </span><span class="token" style="color: #023b95;;--phiki-dark-color: #91cbff">10</span><span class="token">}</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">34</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">35</span><span class="token">        </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Filter out malformed data</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">36</span><span class="token">        </span><span class="token">valid_data</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">=</span><span class="token"> </span><span class="token">[</span><span class="token">entry</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">for</span><span class="token"> </span><span class="token">entry</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">in</span><span class="token"> </span><span class="token">alien_vault_data</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">+</span><span class="token"> </span><span class="token">vt_data</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">if</span><span class="token"> </span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">id</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">'</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">in</span><span class="token"> </span><span class="token">entry</span><span class="token">]</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">37</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">return</span><span class="token"> </span><span class="token">valid_data</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">38</span><span class="token">    </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">except</span><span class="token"> </span><span class="token">APIError</span><span class="token"> </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">as</span><span class="token"> </span><span class="token">e</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">39</span><span class="token">        </span><span class="token">log_error</span><span class="token">(</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">f</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">Failed to fetch threat data: </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">{</span><span class="token">e</span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">}</span><span class="token" style="color: #032563;;--phiki-dark-color: #addcff">"</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="line-number" style="color: #88929d;-webkit-user-select: none">40</span><span class="token">        </span><span class="token" style="color: #a0111f;;--phiki-dark-color: #ff9492">return</span><span class="token"> </span><span class="token">[</span><span class="token">]</span><span class="token">  </span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc">#</span><span class="token" style="color: #66707b;;--phiki-dark-color: #bdc4cc"> Return an empty list on failure</span><span class="token">
</span></span>
```

With that done, all tests should pass once again!

These additional tests help make IntelliSIEM more resilient, reliable, and capable of handling unexpected situations gracefully. Incorporating a testing framework lays the groundwork for future development, helping ensure that we catch issues early and maintain a high level of code quality. Next up, we'll dive in deeper and make sure we have a robust error-handling structure in place.

---

## Navigation

- Parent: [Blog](https://bsb.perryconsulting.net/blog.md)
- Previous: [IntelliSIEM and Test-Driven Development: Creating Robust Error Handling and Log Rotation](https://bsb.perryconsulting.net/blog/intellisiem-and-test-driven-development-creating-robust-error-handling-and-log-rotation.md)
- Next: [Setting Up the Core of IntelliSIEM – Structure, TDD, and API Connection](https://bsb.perryconsulting.net/blog/setting-up-the-core-of-intellisiem-structure-tdd-and-api-connection.md)
