Skip to content

Commit bd2dc36

Browse files
committed
fix: refactor CSV handling in well-inventory steps and add error handling for unsupported file types
1 parent 85ec7fd commit bd2dc36

4 files changed

Lines changed: 60 additions & 25 deletions

File tree

tests/features/data/well-inventory-invalid-filetype.txt

Whitespace-only changes.

tests/features/data/well-inventory-missing-required.csv

Whitespace-only changes.

tests/features/data/well-inventory-no-data-headers.csv

Whitespace-only changes.

tests/features/steps/well-inventory-csv.py

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import csv
22
from datetime import datetime
3+
from pathlib import Path
4+
from typing import List
35

46
from behave import given, when, then
57
from behave.runner import Context
@@ -11,7 +13,7 @@ def step_impl_csv_file_is_encoded_utf8(context: Context):
1113
# context.csv_file.encoding = 'utf-8'
1214
# context.csv_file.separator = ','
1315
with open("tests/features/data/well-inventory-valid.csv", "r") as f:
14-
context.csv_file_content = f.read()
16+
context.file_content = f.read()
1517

1618

1719
@given("valid lexicon values exist for:")
@@ -22,7 +24,11 @@ def step_impl_valid_lexicon_values(context: Context):
2224
@given("my CSV file contains multiple rows of well inventory data")
2325
def step_impl_csv_file_contains_multiple_rows(context: Context):
2426
"""Sets up the CSV file with multiple rows of well inventory data."""
25-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
27+
context.rows = _get_rows(context)
28+
29+
30+
def _get_rows(context: Context) -> List[str]:
31+
return list(csv.DictReader(context.file_content.splitlines()))
2632

2733

2834
@given("the CSV includes required fields:")
@@ -62,10 +68,10 @@ def step_impl(context: Context):
6268
print(f"Optional fields: {optional_fields}")
6369

6470

65-
@when("I upload the CSV file to the bulk upload endpoint")
71+
@when("I upload the file to the bulk upload endpoint")
6672
def step_impl(context: Context):
6773
context.response = context.client.post(
68-
"/well-inventory-csv", data={"file": context.csv_file_content}
74+
"/well-inventory-csv", data={"file": context.file_content}
6975
)
7076

7177

@@ -87,15 +93,13 @@ def step_impl(context: Context):
8793
response_json = context.response.json()
8894
wells = response_json.get("wells", [])
8995
assert len(wells) == len(
90-
context.rows
96+
context.row_count
9197
), "Expected the same number of wells as rows in the CSV"
9298

9399

94100
@given('my CSV file contains rows missing a required field "well_name_point_id"')
95101
def step_impl(context: Context):
96-
with open("tests/features/data/well-inventory-invalid.csv", "r") as f:
97-
context.csv_file_content = f.read()
98-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
102+
_set_file_content(context, "well-inventory-missing-required.csv")
99103

100104

101105
@then("the response includes validation errors for all rows missing required fields")
@@ -127,9 +131,7 @@ def step_impl(context: Context):
127131

128132
@given('my CSV file contains one or more duplicate "well_name_point_id" values')
129133
def step_impl(context: Context):
130-
with open("tests/features/data/well-inventory-duplicate.csv", "r") as f:
131-
context.csv_file_content = f.read()
132-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
134+
_set_file_content(context, "well-inventory-duplicate.csv")
133135

134136

135137
@then("the response includes validation errors indicating duplicated values")
@@ -163,43 +165,76 @@ def step_impl(context: Context):
163165
assert "error" in error, "Expected validation error to include error message"
164166

165167

168+
def _set_file_content(context: Context, name):
169+
path = Path("tests") / "features" / "data" / name
170+
with open(path, "r") as f:
171+
context.file_content = f.read()
172+
if name.endswith(".csv"):
173+
context.rows = _get_rows(context)
174+
175+
166176
@given(
167177
'my CSV file contains invalid lexicon values for "contact_role" or other lexicon fields'
168178
)
169179
def step_impl(context: Context):
170-
with open("tests/features/data/well-inventory-invalid-lexicon.csv", "r") as f:
171-
context.csv_file_content = f.read()
172-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
180+
_set_file_content(context, "well-inventory-invalid-lexicon.csv")
173181

174182

175183
@given('my CSV file contains invalid ISO 8601 date values in the "date_time" field')
176184
def step_impl(context: Context):
177-
with open("tests/features/data/well-inventory-invalid-date.csv", "r") as f:
178-
context.csv_file_content = f.read()
179-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
185+
_set_file_content(context, "well-inventory-invalid-date.csv")
180186

181187

182188
@given(
183189
'my CSV file contains values that cannot be parsed as numeric in numeric-required fields such as "utm_easting"'
184190
)
185191
def step_impl(context: Context):
186-
with open("tests/features/data/well-inventory-invalid-numeric.csv", "r") as f:
187-
context.csv_file_content = f.read()
192+
_set_file_content(context, "well-inventory-invalid-numeric.csv")
188193

189194

190195
@given("my CSV file contains column headers but no data rows")
191196
def step_impl(context: Context):
192-
with open("tests/features/data/well-inventory-no-data.csv", "r") as f:
193-
context.csv_file_content = f.read()
194-
context.rows = csv.DictReader(context.csv_file_content.splitlines())
197+
_set_file_content(context, "well-inventory-no-data-headers.csv")
195198

196199

197200
@given("my CSV file is empty")
198201
def step_impl(context: Context):
199-
context.csv_file_content = ""
202+
context.file_content = ""
200203
context.rows = []
201204

202205

206+
@given("I have a non-CSV file")
207+
def step_impl(context: Context):
208+
_set_file_content(context, "well-inventory-invalid-filetype.txt")
209+
210+
211+
@then("the response includes an error message indicating unsupported file type")
212+
def step_impl(context: Context):
213+
response_json = context.response.json()
214+
assert "error" in response_json, "Expected response to include an error message"
215+
assert (
216+
"Unsupported file type" in response_json["error"]
217+
), "Expected error message to indicate unsupported file type"
218+
219+
220+
@then("the response includes an error message indicating an empty file")
221+
def step_impl(context: Context):
222+
response_json = context.response.json()
223+
assert "error" in response_json, "Expected response to include an error message"
224+
assert (
225+
"Empty file" in response_json["error"]
226+
), "Expected error message to indicate an empty file"
227+
228+
229+
@then("the response includes an error indicating that no data rows were found")
230+
def step_impl(context: Context):
231+
response_json = context.response.json()
232+
assert "error" in response_json, "Expected response to include an error message"
233+
assert (
234+
"No data rows found" in response_json["error"]
235+
), "Expected error message to indicate no data rows were found"
236+
237+
203238
# @given(
204239
# "the system has valid lexicon values for contact_role, contact_type, phone_type, email_type, address_type, elevation_method, well_pump_type, well_purpose, well_hole_status, and monitoring_frequency"
205240
# )
@@ -220,7 +255,7 @@ def step_impl(context: Context):
220255
# nrow = ",".join([row[k] for k in keys])
221256
# nrows.append(nrow)
222257
#
223-
# context.csv_file_content = "\n".join(nrows)
258+
# context.file_content = "\n".join(nrows)
224259
#
225260
#
226261
# @when("I upload the CSV file to the bulk upload endpoint")
@@ -229,7 +264,7 @@ def step_impl(context: Context):
229264
# # Simulate uploading the CSV file to the bulk upload endpoint
230265
# context.response = context.client.post(
231266
# "/bulk-upload/well-inventory",
232-
# files={"file": ("well_inventory.csv", context.csv_file_content, "text/csv")},
267+
# files={"file": ("well_inventory.csv", context.file_content, "text/csv")},
233268
# )
234269
#
235270
#

0 commit comments

Comments
 (0)