This is an automated email from the ASF dual-hosted git repository.

amoeba pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new a2241ecbc test(go,r): add basic Go and R tests for connection profiles 
(#4234)
a2241ecbc is described below

commit a2241ecbc7e0739bd209cba94084e6ab17bd0ec8
Author: Bryce Mecum <[email protected]>
AuthorDate: Sun Apr 19 21:38:54 2026 -0700

    test(go,r): add basic Go and R tests for connection profiles (#4234)
    
    Adds basic tests for connection profiles for the Go and R driver
    managers just to catch regressions and make it easier for people (or
    agents) poking around the codebase to know profiles work in these
    languages. The driver manager tests don't test a real driver+manifest
    combo and just check the we get profile-specific errors and that args
    are passed through. Also adds one test with a real driver to the R
    adbcsqlite package.
---
 go/adbc/drivermgr/profile_test.go                  | 121 ++++++++++++++++++
 r/adbcdrivermanager/tests/testthat/test-profile.R  | 142 +++++++++++++++++++++
 r/adbcsqlite/DESCRIPTION                           |   3 +-
 .../tests/testthat/test-connection-profiles.R      |  87 +++++++++++++
 4 files changed, 352 insertions(+), 1 deletion(-)

diff --git a/go/adbc/drivermgr/profile_test.go 
b/go/adbc/drivermgr/profile_test.go
new file mode 100644
index 000000000..b0fa1c541
--- /dev/null
+++ b/go/adbc/drivermgr/profile_test.go
@@ -0,0 +1,121 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//go:build cgo
+
+package drivermgr_test
+
+import (
+       "os"
+       "path/filepath"
+       "testing"
+
+       "github.com/apache/arrow-adbc/go/adbc/drivermgr"
+       "github.com/stretchr/testify/require"
+)
+
+// simpleProfile references a nonexistent driver. These tests only verify that
+// the profile mechanism routes correctly — i.e., the error comes from failing
+// to load the driver, not from failing to find or parse the profile.
+const simpleProfile = `
+profile_version = 1
+driver = "/nonexistent/driver.so"
+
+[Options]
+`
+
+func writeProfile(t *testing.T, dir, name, content string) string {
+       t.Helper()
+       path := filepath.Join(dir, name+".toml")
+       require.NoError(t, os.WriteFile(path, []byte(content), 0600))
+       return path
+}
+
+// loads a profile via the absolute path in the "profile" option.
+func TestProfileAbsolutePath(t *testing.T) {
+       dir := t.TempDir()
+       profilePath := writeProfile(t, dir, "myprofile", simpleProfile)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "profile": profilePath,
+       })
+       require.ErrorContains(t, err, "nonexistent")
+}
+
+// loads a profile by name using additional_profile_search_path_list.
+func TestProfileByNameViaSearchPath(t *testing.T) {
+       dir := t.TempDir()
+       writeProfile(t, dir, "myprofile", simpleProfile)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "profile":                             "myprofile",
+               "additional_profile_search_path_list": dir,
+       })
+       require.ErrorContains(t, err, "nonexistent")
+}
+
+// loads a profile by name with ADBC_PROFILE_PATH set.
+func TestProfileByNameViaEnvVar(t *testing.T) {
+       dir := t.TempDir()
+       writeProfile(t, dir, "myprofile", simpleProfile)
+
+       t.Setenv("ADBC_PROFILE_PATH", dir)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "profile": "myprofile",
+       })
+       require.ErrorContains(t, err, "nonexistent")
+}
+
+// loads a profile using a profile:// URI in the "uri" key.
+func TestProfileViaURIOption(t *testing.T) {
+       dir := t.TempDir()
+       profilePath := writeProfile(t, dir, "myprofile", simpleProfile)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "uri": "profile://" + profilePath,
+       })
+       require.ErrorContains(t, err, "nonexistent")
+}
+
+// loads a profile using a profile:// URI in the "driver" key.
+func TestProfileViaDriverOption(t *testing.T) {
+       dir := t.TempDir()
+       profilePath := writeProfile(t, dir, "myprofile", simpleProfile)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "driver": "profile://" + profilePath,
+       })
+       require.ErrorContains(t, err, "nonexistent")
+}
+
+// verifies that a missing profile returns an error.
+func TestProfileNotFound(t *testing.T) {
+       dir := t.TempDir()
+       t.Setenv("ADBC_PROFILE_PATH", dir)
+
+       var drv drivermgr.Driver
+       _, err := drv.NewDatabase(map[string]string{
+               "profile": "does_not_exist",
+       })
+       require.ErrorContains(t, err, "Profile not found: does_not_exist")
+}
diff --git a/r/adbcdrivermanager/tests/testthat/test-profile.R 
b/r/adbcdrivermanager/tests/testthat/test-profile.R
new file mode 100644
index 000000000..e78703b67
--- /dev/null
+++ b/r/adbcdrivermanager/tests/testthat/test-profile.R
@@ -0,0 +1,142 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# This suite is just a smoke test to make sure connection profiles are hooked
+# up. We make a fake driver and a broken connection profile just to test that
+# the driver manager is producing the right error message as proof connection
+# profiles are hooked up.
+
+adbc_driver_for_profile <- function() {
+  driver <- new.env(parent = emptyenv())
+  driver$load_flags <- adbc_load_flags()
+  class(driver) <- "adbc_driver"
+  driver
+}
+
+write_profile <- function(dir, name) {
+  content <- paste0(
+    'profile_version = 1\n',
+    'driver = "/nonexistent/driver.so"\n',
+    '\n',
+    '[Options]\n'
+  )
+  path <- file.path(dir, paste0(name, ".toml"))
+  writeLines(content, path)
+  path
+}
+
+test_that("can load a profile by absolute path via 'profile' option", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  profile_path <- write_profile(dir, "myprofile")
+
+  expect_error(
+    adbc_database_init(
+      adbc_driver_for_profile(),
+      profile = profile_path
+    ),
+    regexp = "nonexistent"
+  )
+})
+
+test_that("can load a profile by name via 
additional_profile_search_path_list", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  write_profile(dir, "myprofile")
+
+  expect_error(
+    adbc_database_init(
+      adbc_driver_for_profile(),
+      profile = "myprofile",
+      additional_profile_search_path_list = dir
+    ),
+    regexp = "nonexistent"
+  )
+})
+
+test_that("can load a profile by name via ADBC_PROFILE_PATH env var", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  write_profile(dir, "myprofile")
+
+  withr::with_envvar(
+    list(ADBC_PROFILE_PATH = dir),
+    expect_error(
+      adbc_database_init(
+        adbc_driver_for_profile(),
+        profile = "myprofile"
+      ),
+      regexp = "nonexistent"
+    )
+  )
+})
+
+test_that("can load a profile via profile:// URI in 'uri' option", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  profile_path <- write_profile(dir, "myprofile")
+
+  expect_error(
+    adbc_database_init(
+      adbc_driver_for_profile(),
+      uri = paste0("profile://", profile_path)
+    ),
+    regexp = "nonexistent"
+  )
+})
+
+test_that("can load a profile via profile:// URI in 'driver' option", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  profile_path <- write_profile(dir, "myprofile")
+
+  expect_error(
+    adbc_database_init_default(
+      adbc_driver_for_profile(),
+      list(driver = paste0("profile://", profile_path)) # Wrap in list() to 
avoid arg names clashing
+    ),
+    regexp = "nonexistent"
+  )
+})
+
+test_that("missing profile returns an error", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  withr::with_envvar(
+    list(ADBC_PROFILE_PATH = dir),
+    expect_error(
+      adbc_database_init_default(
+        adbc_driver_for_profile(),
+        list(profile = "does_not_exist")
+      ),
+      # "does_not_exist" is the profile name; keep in sync with C error 
message format
+      regexp = "does_not_exist"
+    )
+  )
+})
diff --git a/r/adbcsqlite/DESCRIPTION b/r/adbcsqlite/DESCRIPTION
index c0c49e93f..2c8735ab5 100644
--- a/r/adbcsqlite/DESCRIPTION
+++ b/r/adbcsqlite/DESCRIPTION
@@ -19,7 +19,8 @@ RoxygenNote: 7.3.2
 SystemRequirements: SQLite3
 Suggests:
     nanoarrow,
-    testthat (>= 3.0.0)
+    testthat (>= 3.0.0),
+    withr
 Config/testthat/edition: 3
 Config/build/bootstrap: TRUE
 URL: https://arrow.apache.org/adbc/current/r/adbcsqlite/, 
https://github.com/apache/arrow-adbc
diff --git a/r/adbcsqlite/tests/testthat/test-connection-profiles.R 
b/r/adbcsqlite/tests/testthat/test-connection-profiles.R
new file mode 100644
index 000000000..e96113fdd
--- /dev/null
+++ b/r/adbcsqlite/tests/testthat/test-connection-profiles.R
@@ -0,0 +1,87 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+adbcsqlite_shared <- function() {
+  lib_name <- paste0("adbcsqlite", .Platform$dynlib.ext)
+  r_arch <- .Platform$r_arch
+
+  path <- if (nzchar(r_arch)) {
+    system.file("libs", r_arch, lib_name, package = "adbcsqlite")
+  } else {
+    system.file("libs", lib_name, package = "adbcsqlite")
+  }
+
+  if (nzchar(path)) {
+    return(path)
+  }
+  system.file("src", lib_name, package = "adbcsqlite")
+}
+
+adbc_driver_for_profile <- function() {
+  driver <- new.env(parent = emptyenv())
+  driver$load_flags <- adbcdrivermanager:::adbc_load_flags()
+  class(driver) <- "adbc_driver"
+  driver
+}
+
+write_sqlite_profile <- function(dir, name) {
+  driver_path <- adbcsqlite_shared()
+  stopifnot(file.exists(driver_path))
+
+  content <- paste0(
+    'profile_version = 1\n',
+    'driver = "',
+    driver_path,
+    '"\n',
+    '[Options]\n'
+  )
+  path <- file.path(dir, paste0(name, ".toml"))
+  writeLines(content, path)
+  stopifnot(file.exists(path))
+
+  path
+}
+
+test_that("can open a sqlite database via a profile from path via env var", {
+  dir <- tempfile()
+  dir.create(dir)
+  on.exit(unlink(dir, recursive = TRUE))
+
+  profile_path <- write_sqlite_profile(dir, "my_sqlite")
+  dir <- dirname(profile_path)
+
+  withr::with_envvar(
+    list(ADBC_PROFILE_PATH = dir),
+    db <- adbc_database_init(
+      adbc_driver_for_profile(),
+      uri = "profile://my_sqlite"
+    ),
+  )
+
+  con <- adbcdrivermanager::adbc_connection_init(db)
+  on.exit({
+    adbcdrivermanager::adbc_connection_release(con)
+    adbcdrivermanager::adbc_database_release(db)
+  })
+
+  stream <- adbcdrivermanager::read_adbc(con, "SELECT 1 AS numbers")
+
+  expect_identical(
+    as.data.frame(stream),
+    data.frame(numbers = 1, check.names = FALSE)
+  )
+})

Reply via email to