diff --git a/DESCRIPTION b/DESCRIPTION index 5536568..d02273c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -45,3 +45,6 @@ Collate: 'error.R' Depends: R (>= 4.3.0) +Suggests: + testthat (>= 3.0.0) +Config/testthat/edition: 3 diff --git a/Dockerfile b/Dockerfile index 617197a..69a66be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ RUN R -e "install.packages('gdalcubes')" # install other necessary packages RUN apt-get install -y libsodium-dev libudunits2-dev -RUN Rscript -e "install.packages(c('plumber', 'useful', 'ids', 'R6', 'sf', 'rstac','bfast'))" +RUN Rscript -e "install.packages(c('plumber', 'useful', 'ids', 'R6', 'sf', 'rstac','bfast', 'spsUtil'))" # create directories RUN mkdir -p /opt/dockerfiles/ && mkdir -p /var/openeo/workspace/ && mkdir -p /var/openeo/workspace/data/ @@ -26,4 +26,4 @@ RUN Rscript -e "remotes::install_local('/opt/dockerfiles',dependencies=TRUE)" # cmd or entrypoint for startup CMD ["R", "-q", "--no-save", "-f /opt/dockerfiles/startProduction.R"] -EXPOSE 8000 \ No newline at end of file +EXPOSE 8000 diff --git a/startLocal.R b/startLocal.R index d32e807..297cb01 100644 --- a/startLocal.R +++ b/startLocal.R @@ -1,5 +1,8 @@ # build and install package locally (use for development) -remotes::install_local("./", dependencies = TRUE, force = TRUE) +remotes::install_local("./", dependencies = FALSE, force = TRUE) + +# run test for processes of the package +test_res = devtools::test(stop_on_failure = TRUE) # Start service library(openeocubes) diff --git a/tests/testthat.R b/tests/testthat.R new file mode 100644 index 0000000..64119a7 --- /dev/null +++ b/tests/testthat.R @@ -0,0 +1,12 @@ +# This file is part of the standard setup for testthat. +# It is recommended that you do not modify it. +# +# Where should you do additional test configuration? +# Learn more about the roles of various files in: +# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview +# * https://testthat.r-lib.org/articles/special-files.html + +library(testthat) +library(openeocubes) + +test_check("openeocubes") diff --git a/tests/testthat/file b/tests/testthat/file new file mode 100644 index 0000000..e69de29 diff --git a/tests/testthat/test-apply_prediction.R b/tests/testthat/test-apply_prediction.R new file mode 100644 index 0000000..40431cb --- /dev/null +++ b/tests/testthat/test-apply_prediction.R @@ -0,0 +1,23 @@ +test_that("apply prediction works", { + + # create Session-object for testing + config <- SessionConfig(api.port = 8000, host = "127.0.0.1") + + # set workspace for testing + config$workspace.path = paste0(getwd(),"/", test_path("testData")) + + # this silently returns "Session" + createSessionInstance(config) + + expected_bands = c("predicted_class", "class_confidence") + expected_classes = c("apply_pixel_cube", "cube", "xptr") + + datacube = test_path("testData", "train_model_test_cube.nc") |> gdalcubes::ncdf_cube() + + # "myModel" must exist in the Session workspace path + prediction_datacube = spsUtil::quiet(apply_prediction_opp(datacube, model_id = "myModel")) + + + expect_equal(class(prediction_datacube), expected_classes) + expect_equal(names(prediction_datacube), expected_bands) +}) diff --git a/tests/testthat/test-train_model.R b/tests/testthat/test-train_model.R new file mode 100644 index 0000000..4a07010 --- /dev/null +++ b/tests/testthat/test-train_model.R @@ -0,0 +1,37 @@ +test_that("train model works", { + + # create Session-object for testing + config <- SessionConfig(api.port = 8000, host = "127.0.0.1") + + # set workspace for testing + config$workspace.path = base::paste0(base::getwd(),"/", test_path("testData")) + + # this silently returns "Session" + createSessionInstance(config) + + datacube = gdalcubes::ncdf_cube(test_path("testData", "train_model_test_cube.nc")) + + training_data_path = test_path("testData", "classes.geojson") + training_data = sf::st_read(training_data_path, quiet = TRUE) + + training_data_class_levels = base::unique(training_data$class) |> + base::as.numeric() |> + base::sort() + + model = spsUtil:::quiet(train_model_opp( + data = datacube, + model_type = "RF", + labeled_polygons = training_data_path, + hyperparameters = base::list(mtry = 5, ntree = 50), + )) + + # get model class levels and parse Integer value + model_class_levels = base::levels(model$finalModel$y) |> + base::as.character() |> + stringr::str_extract_all("\\d+") |> + base::as.numeric() |> + base::sort() + + expect_equal(class(model), c("train", "train.formula")) + expect_equal(model_class_levels, training_data_class_levels) +}) diff --git a/tests/testthat/testData/classes.geojson b/tests/testthat/testData/classes.geojson new file mode 100644 index 0000000..4b46cd2 --- /dev/null +++ b/tests/testthat/testData/classes.geojson @@ -0,0 +1,12 @@ +{ +"type": "FeatureCollection", +"name": "demo_training_data", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "class": 1 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 7.689557844550476, 51.949452468942482 ], [ 7.688892820575198, 51.949026810046234 ], [ 7.688995131956011, 51.947686746399938 ], [ 7.690990203881843, 51.948601147109812 ], [ 7.693778189008965, 51.948616912475792 ], [ 7.695517482482767, 51.949956948328605 ], [ 7.695645371708782, 51.950319539382036 ], [ 7.694443212984243, 51.951013183663179 ], [ 7.696003461541622, 51.951943280746399 ], [ 7.695798838779998, 51.952305855739226 ], [ 7.694340901603431, 51.952274327595376 ], [ 7.692499296748817, 51.950792479828458 ], [ 7.693113165033688, 51.950256480278995 ], [ 7.692192362606382, 51.949673179372205 ], [ 7.689660155931289, 51.949531294220662 ], [ 7.689557844550476, 51.949452468942482 ] ] ] } }, +{ "type": "Feature", "properties": { "class": 1 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 7.689212543640235, 51.95613636025216 ], [ 7.688266163367726, 51.954575823841481 ], [ 7.693023642575478, 51.952400440037813 ], [ 7.693611933015146, 51.95279453913448 ], [ 7.692205151528981, 51.954055632967936 ], [ 7.690619325126397, 51.954292084113142 ], [ 7.690082190377137, 51.954828035425976 ], [ 7.691156459875661, 51.956152122969122 ], [ 7.689212543640235, 51.95613636025216 ] ] ] } }, +{ "type": "Feature", "properties": { "class": 2 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 7.697320720569576, 51.952416204068179 ], [ 7.695402382179351, 51.951092006198067 ], [ 7.697013786427139, 51.949752004262422 ], [ 7.697397454105184, 51.949893888715664 ], [ 7.697320720569576, 51.952416204068179 ] ] ] } }, +{ "type": "Feature", "properties": { "class": 3 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 7.689979878996324, 51.952778775237121 ], [ 7.689928723305917, 51.951785638530744 ], [ 7.691898217386547, 51.9512338864117 ], [ 7.692256307219387, 51.952195507138718 ], [ 7.689979878996324, 51.952778775237121 ] ] ] } }, +{ "type": "Feature", "properties": { "class": 4 }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 7.697371876259982, 51.949468234009203 ], [ 7.696860319355923, 51.949231757426539 ], [ 7.695862783393008, 51.949736239295468 ], [ 7.695786049857396, 51.949625884371564 ], [ 7.696783585820314, 51.949089870878382 ], [ 7.697474187640793, 51.949310583092625 ], [ 7.697371876259982, 51.949468234009203 ] ] ] } } +] +} diff --git a/tests/testthat/testData/cube.nc b/tests/testthat/testData/cube.nc new file mode 100644 index 0000000..d026e33 Binary files /dev/null and b/tests/testthat/testData/cube.nc differ diff --git a/tests/testthat/testData/myModel.rds b/tests/testthat/testData/myModel.rds new file mode 100644 index 0000000..bc3c009 Binary files /dev/null and b/tests/testthat/testData/myModel.rds differ diff --git a/tests/testthat/testData/train_model_test_cube.nc b/tests/testthat/testData/train_model_test_cube.nc new file mode 100644 index 0000000..1694145 Binary files /dev/null and b/tests/testthat/testData/train_model_test_cube.nc differ