Skip to content

Commit 7df3f8d

Browse files
committed
updating tests for water atlas api functions
1 parent 1067f0a commit 7df3f8d

4 files changed

Lines changed: 169 additions & 80 deletions

File tree

R/read_importwqwa.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ read_importwqwa <- function(dataSource, parameter, start_date = NULL, end_date =
5454
item <- jsonlite::fromJSON(i)
5555
out <- append(out, list(item), after = length(out))
5656
}, error = function(e) {
57-
cat(sprintf("Error parsing JSON line: %s\n", e$message))
57+
stop(sprintf("Error parsing JSON line: %s\n", e$message))
5858
})
5959
}
6060
}
61-
61+
6262
out <- dplyr::bind_rows(out) |>
6363
dplyr::mutate(
6464
activityStartDate = as.Date(activityStartDate)

R/util_importwqwa.R

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ util_importwqwa <- function(endpoint, pageSize = 10000, waterbodyId = NULL){
4747
out <- dplyr::bind_rows(data$items)
4848

4949
totpages <- data$totalPages
50-
failed_pages <- c()
5150

5251
if(totpages > 1){
5352

@@ -64,8 +63,7 @@ util_importwqwa <- function(endpoint, pageSize = 10000, waterbodyId = NULL){
6463
out <- dplyr::bind_rows(out, outi)
6564

6665
}, error = function(e) {
67-
failed_pages <<- c(failed_pages, i)
68-
cat("Page", i, "of", totpages, "failed:", httr::status_code(response), "\n")
66+
cat("Page", i, "of", totpages, "failed\n")
6967
})
7068
}
7169
}
Lines changed: 101 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,141 @@
1-
# Mock response helper function
2-
create_mock_response <- function(status_code = 200, items = list(), total_pages = 1) {
1+
# Mock response helper function for NDJSON
2+
create_mock_ndjson_response <- function(status_code = 200, ndjson_content = "") {
33
response <- list()
44
class(response) <- "response"
5-
6-
# Mock the status code
75
attr(response, "status_code") <- status_code
8-
9-
# Mock the content
10-
content_data <- list(
11-
items = items,
12-
totalPages = total_pages
13-
)
14-
15-
return(list(response = response, content = content_data))
6+
return(list(response = response, content = ndjson_content))
167
}
178

18-
test_that("util_importwqwa validates endpoint argument", {
19-
expect_error(
20-
util_importwqwa("invalid_endpoint"),
21-
"'arg' should be one of"
9+
test_that("read_importwqwa processes basic NDJSON response", {
10+
# Mock NDJSON content
11+
ndjson_content <- '{"id": 1, "value": 10.5, "activityStartDate": "2023-01-01"}
12+
{"id": 2, "value": 12.3, "activityStartDate": "2023-01-02"}'
13+
14+
mock_data <- create_mock_ndjson_response(200, ndjson_content)
15+
16+
# Create a proper data frame with the activityStartDate column
17+
mock_df <- data.frame(
18+
id = c(1, 2),
19+
value = c(10.5, 12.3),
20+
activityStartDate = c("2023-01-01", "2023-01-02"),
21+
stringsAsFactors = FALSE
2222
)
23-
})
24-
25-
test_that("util_importwqwa handles single page response", {
26-
# Mock data
27-
mock_items <- list(
28-
list(id = 1, name = "Item 1"),
29-
list(id = 2, name = "Item 2")
30-
)
31-
32-
mock_data <- create_mock_response(200, mock_items, 1)
3323

34-
# Mock httr functions
24+
# Mock functions
3525
mock_get <- mock(mock_data$response)
3626
mock_stop_for_status <- mock()
37-
mock_content <- mock(mock_data$content)
38-
39-
# Mock dplyr::bind_rows to return a simple data frame
40-
mock_bind_rows <- mock(data.frame(id = c(1, 2), name = c("Item 1", "Item 2")))
27+
mock_content <- mock(ndjson_content)
28+
mock_fromJSON <- mock(
29+
list(id = 1, value = 10.5, activityStartDate = "2023-01-01"),
30+
list(id = 2, value = 12.3, activityStartDate = "2023-01-02")
31+
)
32+
mock_bind_rows <- mock(mock_df)
4133

4234
# Apply stubs
43-
stub(util_importwqwa, "httr::GET", mock_get)
44-
stub(util_importwqwa, "httr::stop_for_status", mock_stop_for_status)
45-
stub(util_importwqwa, "httr::content", mock_content)
46-
stub(util_importwqwa, "dplyr::bind_rows", mock_bind_rows)
35+
stub(read_importwqwa, "httr::GET", mock_get)
36+
stub(read_importwqwa, "httr::stop_for_status", mock_stop_for_status)
37+
stub(read_importwqwa, "httr::content", mock_content)
38+
stub(read_importwqwa, "jsonlite::fromJSON", mock_fromJSON)
39+
stub(read_importwqwa, "dplyr::bind_rows", mock_bind_rows)
4740

48-
result <- util_importwqwa("parameters")
41+
# Suppress trace output for testing
42+
result <- suppressMessages(read_importwqwa("WIN_21FLHILL", "Chla_ugl", trace = FALSE))
4943

5044
# Verify the result
5145
expect_equal(nrow(result), 2)
5246
expect_equal(result$id, c(1, 2))
47+
expect_true("activityStartDate" %in% names(result))
5348

54-
# Verify mocks were called correctly
49+
# Verify mocks were called
5550
expect_called(mock_get, 1)
5651
expect_called(mock_stop_for_status, 1)
5752
expect_called(mock_content, 1)
53+
expect_called(mock_fromJSON, 2) # Once for each JSON line
5854
})
5955

60-
test_that("util_importwqwa handles multiple pages", {
61-
# Mock data for first page
62-
mock_items_page1 <- list(list(id = 1, name = "Item 1"))
63-
mock_items_page2 <- list(list(id = 2, name = "Item 2"))
56+
test_that("read_importwqwa includes optional date parameters", {
57+
mock_data <- create_mock_ndjson_response(200, '{"id": 1, "activityStartDate": "2023-01-01"}')
6458

65-
mock_data_page1 <- create_mock_response(200, mock_items_page1, 2)
66-
mock_data_page2 <- create_mock_response(200, mock_items_page2, 2)
59+
# Create proper data frame with activityStartDate column
60+
mock_df <- data.frame(id = 1, activityStartDate = "2023-01-01", stringsAsFactors = FALSE)
6761

68-
# Mock httr functions
69-
mock_get <- mock(mock_data_page1$response, mock_data_page2$response)
70-
mock_stop_for_status <- mock()
71-
mock_content <- mock(mock_data_page1$content, mock_data_page2$content)
62+
# Capture the query parameters
63+
mock_get <- mock(mock_data$response, side_effect = function(url, query) {
64+
captured_query <<- query
65+
return(mock_data$response)
66+
})
7267

73-
# Mock dplyr::bind_rows
74-
mock_bind_rows <- mock(
75-
data.frame(id = 1, name = "Item 1"), # First call for page 1
76-
data.frame(id = 2, name = "Item 2"), # Second call for page 2
77-
data.frame(id = c(1, 2), name = c("Item 1", "Item 2")) # Final bind
78-
)
68+
mock_stop_for_status <- mock()
69+
mock_content <- mock('{"id": 1, "activityStartDate": "2023-01-01"}')
70+
mock_fromJSON <- mock(list(id = 1, activityStartDate = "2023-01-01"))
71+
mock_bind_rows <- mock(mock_df)
7972

8073
# Apply stubs
81-
stub(util_importwqwa, "httr::GET", mock_get)
82-
stub(util_importwqwa, "httr::stop_for_status", mock_stop_for_status)
83-
stub(util_importwqwa, "httr::content", mock_content)
84-
stub(util_importwqwa, "dplyr::bind_rows", mock_bind_rows)
85-
86-
result <- util_importwqwa("waterbodies")
87-
88-
# Verify the result
89-
expect_equal(nrow(result), 2)
74+
stub(read_importwqwa, "httr::GET", mock_get)
75+
stub(read_importwqwa, "httr::stop_for_status", mock_stop_for_status)
76+
stub(read_importwqwa, "httr::content", mock_content)
77+
stub(read_importwqwa, "jsonlite::fromJSON", mock_fromJSON)
78+
stub(read_importwqwa, "dplyr::bind_rows", mock_bind_rows)
79+
80+
result <- suppressMessages(
81+
read_importwqwa("WIN_21FLHILL", "Chla_ugl", "2023-01-01", "2023-02-01", trace = FALSE)
82+
)
9083

91-
# Verify GET was called twice (once for each page)
92-
expect_called(mock_get, 2)
93-
expect_called(mock_stop_for_status, 2)
94-
expect_called(mock_content, 2)
84+
# Verify parameters were included
85+
expect_equal(result$activityStartDate, as.Date("2023-01-01"))
9586
})
9687

97-
test_that("util_importwqwa handles HTTP errors gracefully", {
98-
# Mock a failed response
88+
test_that("read_importwqwa handles HTTP errors", {
9989
mock_response <- list()
10090
class(mock_response) <- "response"
101-
attr(mock_response, "status_code") <- 500
91+
attr(mock_response, "status_code") <- 404
10292

10393
mock_get <- mock(mock_response)
104-
mock_stop_for_status <- mock(stop("HTTP 500 Internal Server Error"))
94+
mock_stop_for_status <- mock(stop("HTTP 404 Not Found"))
95+
96+
# Apply stubs
97+
stub(read_importwqwa, "httr::GET", mock_get)
98+
stub(read_importwqwa, "httr::stop_for_status", mock_stop_for_status)
99+
100+
expect_error(
101+
suppressMessages(read_importwqwa("INVALID", "INVALID", trace = FALSE)),
102+
"HTTP 404 Not Found"
103+
)
104+
})
105+
106+
test_that("read_importwqwa handles malformed JSON gracefully", {
107+
# Mix of valid and invalid JSON
108+
ndjson_content <- '{"id": 1, "value": 10.5}
109+
{invalid json}
110+
{"id": 2, "value": 12.3}'
111+
112+
mock_data <- create_mock_ndjson_response(200, ndjson_content)
113+
114+
# Create data frame without activityStartDate since it's not in the test data
115+
mock_df <- data.frame(id = c(1, 2), value = c(10.5, 12.3), stringsAsFactors = FALSE)
116+
117+
mock_get <- mock(mock_data$response)
118+
mock_stop_for_status <- mock()
119+
mock_content <- mock(ndjson_content)
120+
121+
# Mock fromJSON to succeed twice and fail once
122+
mock_fromJSON <- mock(
123+
list(id = 1, value = 10.5),
124+
stop("Invalid JSON"),
125+
list(id = 2, value = 12.3)
126+
)
127+
128+
mock_bind_rows <- mock(mock_df)
105129

106130
# Apply stubs
107-
stub(util_importwqwa, "httr::GET", mock_get)
108-
stub(util_importwqwa, "httr::stop_for_status", mock_stop_for_status)
131+
stub(read_importwqwa, "httr::GET", mock_get)
132+
stub(read_importwqwa, "httr::stop_for_status", mock_stop_for_status)
133+
stub(read_importwqwa, "httr::content", mock_content)
134+
stub(read_importwqwa, "jsonlite::fromJSON", mock_fromJSON)
135+
stub(read_importwqwa, "dplyr::bind_rows", mock_bind_rows)
109136

110137
expect_error(
111-
util_importwqwa("parameters"),
112-
"HTTP 500 Internal Server Error"
138+
suppressMessages(read_importwqwa("WIN_21FLHILL", "Chla_ugl", trace = FALSE)),
139+
"Error parsing JSON line: Invalid JSON"
113140
)
114141
})

tests/testthat/test-util_importwqwa.R

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,68 @@ test_that("util_importwqwa handles HTTP errors gracefully", {
133133
util_importwqwa("parameters"),
134134
"HTTP 500 Internal Server Error"
135135
)
136-
})
136+
})
137+
138+
test_that("util_importwqwa handles failed pages and outputs error message", {
139+
# Mock data for first page (successful)
140+
mock_items_page1 <- list(list(id = 1, name = "Item 1"))
141+
mock_data_page1 <- create_mock_response(200, mock_items_page1, 3) # 3 total pages
142+
143+
# Mock failed response for page 2
144+
mock_failed_response <- list()
145+
class(mock_failed_response) <- "response"
146+
attr(mock_failed_response, "status_code") <- 500
147+
148+
# Mock successful response for page 3
149+
mock_items_page3 <- list(list(id = 3, name = "Item 3"))
150+
mock_data_page3 <- create_mock_response(200, mock_items_page3, 3)
151+
152+
# Mock httr functions - page 1 succeeds, page 2 fails, page 3 succeeds
153+
mock_get <- mock(
154+
mock_data_page1$response, # Page 1 - success
155+
mock_failed_response, # Page 2 - failure
156+
mock_data_page3$response # Page 3 - success
157+
)
158+
159+
# stop_for_status will be called 3 times, but only throw error on page 2
160+
mock_stop_for_status <- mock(
161+
NULL, # Page 1 - no error
162+
stop("HTTP 500 Internal Server Error"), # Page 2 - error
163+
NULL # Page 3 - no error
164+
)
165+
166+
mock_content <- mock(
167+
mock_data_page1$content, # Page 1 content
168+
mock_data_page3$content # Page 3 content (page 2 skipped due to error)
169+
)
170+
171+
# Mock dplyr::bind_rows - will be called for page 1, then for combining page 1 + page 3
172+
mock_bind_rows <- mock(
173+
data.frame(id = 1, name = "Item 1"), # Page 1 initial result
174+
data.frame(id = 3, name = "Item 3"), # Page 3 result
175+
data.frame(id = c(1, 3), name = c("Item 1", "Item 3")) # Final combined result
176+
)
177+
178+
# Apply stubs
179+
stub(util_importwqwa, "httr::GET", mock_get)
180+
stub(util_importwqwa, "httr::stop_for_status", mock_stop_for_status)
181+
stub(util_importwqwa, "httr::content", mock_content)
182+
stub(util_importwqwa, "dplyr::bind_rows", mock_bind_rows)
183+
184+
# Capture console output to verify error message
185+
output <- capture.output({
186+
result <- util_importwqwa("waterbodies")
187+
})
188+
189+
# Verify the result includes data from successful pages (1 and 3)
190+
expect_equal(nrow(result), 2)
191+
expect_equal(result$id, c(1, 3))
192+
193+
# Verify error message was printed for failed page
194+
expect_true(any(grepl("Page 2 of 3 failed", output)))
195+
196+
# Verify all HTTP calls were made
197+
expect_called(mock_get, 3)
198+
expect_called(mock_stop_for_status, 3)
199+
expect_called(mock_content, 2) # Only called for successful pages
200+
})

0 commit comments

Comments
 (0)