diff --git a/CHANGELOG.md b/CHANGELOG.md index 485e806bd957d5cc8b8a314c3661e707c5ca6378..b5fe7680ae1ec2f68631826fe246c539a1de036a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Basic functionality to establish connection to a CaosDB server and retrieve its version (using the Extern C interface of caosdb-cpplib) * Support for Windows +* Support for config files +* Minimal error handling ### Changed diff --git a/HUMANS.md b/HUMANS.md index 66ee100df5c191da88717f9c96faaf7ce736dc41..5b0e914eddb78f8c5ccd69cd89c58c57b1c5687e 100644 --- a/HUMANS.md +++ b/HUMANS.md @@ -1,3 +1,4 @@ # Active Contributors +* Alexander Kreft * Florian Spreckelsen <f.spreckelsen@indiscale.com> diff --git a/Manifest.toml b/Manifest.toml index f45eecff031feeb9bb67f87c4794b44cc53a293d..663c54166d2aec89522e49737d9c75683f2ecf74 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -1,2 +1,7 @@ # This file is machine-generated - editing it directly is not advised +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" diff --git a/Project.toml b/Project.toml index a389dd0b783b124879da8597b3f6b5215beb4481..a17b1d50149fa14067e15ab9c8523b4b3cdbbafb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,8 @@ name = "CaosDB" uuid = "091fdcf5-a163-4d8f-97f4-9adce40cd04e" authors = ["florian <f.spreckelsen@inidscale.com>"] -version = "0.0.1" +version = "0.0.2" + +[deps] +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" diff --git a/README.md b/README.md index b02135c295d186b9aa988157e4ab9cb33409b936..3fadc0c69386b1db306dec85cfc4c3a5550c00f2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ client library for CaosDB and a part of the CaosDB project. ## Setup Please read the [README\_SETUP.md](README_SETUP.md) for instructions -on how to develop, build, and use this code. +on how to develop, build, and use this code. caosdb-julialib is +developped and tested using Julia 1.6, we cannot guarantee its +compatibility with versions <= 1.5. ## Further reading diff --git a/src/CaosDB.jl b/src/CaosDB.jl index f8bf67eb4593ee58e0bc8d49dfcd776ae6b616ed..906400025ea1e789254dcb8539c1600be3aebf1a 100644 --- a/src/CaosDB.jl +++ b/src/CaosDB.jl @@ -3,6 +3,7 @@ # # Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com> +# Copyright (C) 2021 Alexander Kreft # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -23,10 +24,75 @@ module CaosDB +using Libdl + """ Chose the name of the library according to the OS you're running. """ library_name = (@static Sys.iswindows() ? "ccaosdb" : "libccaosdb") +if isempty(find_library(library_name)) + @error "Could not find $library_name" +end + +module Exceptions + +export evaluate_return_code, CaosDBException, GenericCaosDBException, CaosDBMessage + +using Logging +using CaosDB + +""" +The parent type of all CaosDB errors that can also be used for testing. +""" +abstract type CaosDBException <: Exception end + +""" +A generic exception that will be raised in case of non-zero return +values of the calls to libccaosdb. May carry a message string and a +code. +""" +struct GenericCaosDBException <: CaosDBException + msg::String + code::Cint +end + +Base.showerror(io::IO, e::CaosDBException) = + print(io, "CaosDBException: ", e.msg, " (Status code ", e.code, ")") + +""" +Struct containing Messages and codes for status codes<0 that do not +correspond to errors or success. +""" +struct CaosDBMessage + msg::String + code::Cint +end + +Base.show(io::IO, m::CaosDBMessage) = print(io, m.msg, " (Status code ", m.code, ")") + +""" + function evaluate_return_code(code::Cint) + +Evaluate the return code of a libccaosdb ccall and raise a +`GenericCaosDBException` in case of a non-zero return code. +""" +function evaluate_return_code(code::Cint) + if code != 0 + msg = ccall( + (:caosdb_get_status_description, CaosDB.library_name), + Cstring, + (Cint,), + code, + ) + if code > 0 + throw(GenericCaosDBException(unsafe_string(msg), code)) + else + @info CaosDBMessage(unsafe_string(msg), code) + end + end +end + +end # Exceptions module Info @@ -92,13 +158,13 @@ authenticator object from a configuration. mutable struct _Authenticator wrapped_authenticator::Ptr{Cvoid} - function _Authenticator() + function _Authenticator(managed_by_julia::Bool = false) auth = new() - # force this to point to C_NULL after initialization - auth.wrapped_authenticator = C_NULL - function f(t) - if t.wrapped_authenticator != C_NULL - # Only if pointer was filled after real initialization + if managed_by_julia + # Only append a finalizer for this if the object is + # actually managed by Julia and not created and destroyed + # internally by libcaosdb. + function f(t) ccall( (:caosdb_authentication_delete_authenticator, CaosDB.library_name), Cint, @@ -106,8 +172,9 @@ mutable struct _Authenticator Ref{_Authenticator}(t), ) end + finalizer(f, auth) end - finalizer(f, auth) + return auth end end @@ -126,7 +193,7 @@ function create_plain_password_authenticator( password::AbstractString, ) - auth = Ref{_Authenticator}(_Authenticator()) + auth = Ref{_Authenticator}(_Authenticator(true)) err_code = ccall( (:caosdb_authentication_create_plain_password_authenticator, CaosDB.library_name), @@ -137,11 +204,7 @@ function create_plain_password_authenticator( password, ) - if err_code != 0 - - @error "Creating authenticator failed with code $err_code" - - end + CaosDB.Exceptions.evaluate_return_code(err_code) return auth @@ -149,365 +212,7 @@ end end # Authentication -module Connection - -using ..CaosDB - -export connect - -""" -Struct containing the actual connection to a CaosDB server. Meant for -internal use; call a `CaosDB.Connection.create_<connection>` function -to create an connection object from a configuration. -""" -mutable struct _Connection - wrapped_connection::Ptr{Cvoid} - - function _Connection() - conn = new() - conn.wrapped_connection = C_NULL - function f(t) - if t.wrapped_connection != C_NULL - ccall( - (:caosdb_connection_delete_connection, CaosDB.library_name), - Cint, - (Ref{_Connection},), - Ref{_Connection}(t), - ) - end - end - finalizer(f, conn) - end -end - -""" -Struct containing a pointer to the wrapped cpp class providing the -certificate provider. Meant for internal use; call a -`CaosDB.Connection.create_<certificate_provider>` function to create -an certificate-provider object from a configuration. -""" -mutable struct _CertificateProvider - wrapped_certificate_provider::Ptr{Cvoid} - - function _CertificateProvider() - prov = new() - prov.wrapped_certificate_provider = C_NULL - function f(t) - if t.wrapped_certificate_provider != C_NULL - ccall( - (:caosdb_connection_delete_certificate_provider, CaosDB.library_name), - Cint, - (Ref{_CertificateProvider},), - Ref{_CertificateProvider}(t), - ) - end - end - finalizer(f, prov) - end -end - -""" -Struct containing a pointer to the wrapped cpp class for storing the -connection configuration. Meant for internal use; call a -`CaosDB.Connection.create_<configuration>` function to create -an connection-configuration object from a configuration. -""" -mutable struct _Configuration - wrapped_connection_configuration::Ptr{Cvoid} - - function _Configuration() - config = new() - config.wrapped_connection_configuration = C_NULL - function f(t) - if t.wrapped_connection_configuration != C_NULL - ccall( - ( - :caosdb_connection_delete_connection_configuration, - CaosDB.library_name, - ), - Cint, - (Ref{_Configuration},), - Ref{_Configuration}(t), - ) - end - end - finalizer(f, config) - end -end - -""" - create_pem_file_certificate_provider(path::AbstractString) - -Return a `_CertificateProvider` for the pem certificate located at -`path`. -""" -function create_pem_file_certificate_provider(path::AbstractString) - - cert_provider = Ref{_CertificateProvider}(_CertificateProvider()) - - err_code = ccall( - (:caosdb_connection_create_pem_file_certificate_provider, CaosDB.library_name), - Cint, - (Ref{_CertificateProvider}, Cstring), - cert_provider, - path, - ) - - if err_code != 0 - - @error "PEM certificate creation returned code $err_code." - - end - - return cert_provider - -end - -""" - create_tls_connection_configuration( - host::AbstractString, - port::Cint, - authenticator::Ref{CaosDB.Authentication._Authenticator}, - provider::Ref{_CertificateProvider} - ) - -Return a TLS connection configuration with authentication. -""" -function create_tls_connection_configuration( - host::AbstractString, - port::Cint, - authenticator::Ref{CaosDB.Authentication._Authenticator}, - provider::Ref{_CertificateProvider}, -) - - config = Ref{_Configuration}(_Configuration()) - - err_code = ccall( - (:caosdb_connection_create_tls_connection_configuration, CaosDB.library_name), - Cint, - ( - Ref{_Configuration}, - Cstring, - Cint, - Ref{CaosDB.Authentication._Authenticator}, - Ref{_CertificateProvider}, - ), - config, - host, - port, - authenticator, - provider, - ) - - if err_code != 0 - - @error "TLS-configuration creation returned code $err_code." - - end - - return config - -end - -function create_insecure_connection_configuration(host::AbstractString, port::Cint) - - config = Ref{_Configuration}(_Configuration()) - - err_code = ccall( - (:caosdb_connection_create_insecure_connection_configuration, CaosDB.library_name), - Cint, - (Ref{_Configuration}, Cstring, Cint), - config, - host, - port, - ) - - if err_code != 0 - - @error "Insecure configuration creation returned code $err_code." - - end - - return config -end - -""" - create_connection(config::Ref{_Configuration}) - -Return a connection based on the given `config`. -""" -function create_connection(config::Ref{_Configuration}) - - connection = Ref{_Connection}(_Connection()) - - err_code = ccall( - (:caosdb_connection_create_connection, CaosDB.library_name), - Cint, - (Ref{_Connection}, Ref{_Configuration}), - connection, - config, - ) - - if err_code != 0 - - @error "Creating connection failed with code $err_code." - - end - - return connection - -end - -""" - get_version_info(con::Ref{_Connection}) - -Return the version of the CaosDB server that `con` is connected -to. -""" -function get_version_info(con::Ref{_Connection}) - - info = Ref{CaosDB.Info._VersionInfo}(CaosDB.Info._VersionInfo()) - - err_code = ccall( - (:caosdb_connection_get_version_info, CaosDB.library_name), - Cint, - (Ref{CaosDB.Info._VersionInfo}, Ref{_Connection}), - info, - con, - ) - - # TODO Real error-code handling - if err_code != 0 - - @error "Version info returned with code $err_code" - - end - - return info - -end - -""" - print_version_info(con::Ref{_Connection}) - -Retrieve the version info for the CaosDB server `con` is connected to, -and print the version in a nice message. -""" -function print_version_info(con::Ref{_Connection}) - - # Dereference to access the fields - info = get_version_info(con)[] - - major = info.major - minor = info.minor - patch = info.patch - pre_release_str = unsafe_string(info.pre_release) - build_str = unsafe_string(info.build) - - println( - "Connected to a CaosDB server with version $major.$minor.$patch-$pre_release_str-$build_str.", - ) - -end - -""" - function connect([; - host::AbstractString="", - port_str::AbstractString="undefined", - cacert::AbstractString="", - username::AbstractString="", - password::AbstractString="undefined"] - ) - -Return a connection object created for the given `host`:`port` with an -SSL certificate located at `cacert` with the given credentials. - -# Extended help - -!!! info - - Because of type-stability, and since an empty string may be a - valid password, the value of `password`, for which it is fetched - from an environmental variable, is "undefined". This means that if - you absolutely must use "undefined" as your password, you have to - specify it via the `CAOSDB_PASSWORD` variable. - -# Arguments -- `host::AbstractString=""`: The hostname of the CaosDB server. If - none is provided, the `CAOSDB_SERVER_HOST` environmental variable is - used instead. If that's not defined, "localhost" is used. -- `port_str::AbstractString="undefined"`: The port of the CaosDB - server, given as string. If none is provided, the - `CAOSDB_SERVER_GRPC_PORT_HTTPS` environmental variable is used - instead. If that's not defined, "8443" is used. The default value is - "undefined" rather than an empty string because an empty string - could be a valid port, too, i.e. the CaosDB server is available at - `host` without a port. -- `cacert::AbstractString=""`: The path to the SSL certificate of the - CaosDB server. If none is provided, the `CAOSDB_SERVER_CERT` - environmental variable is used instead. -- `username::AbstractString=""`: The username with which to log in - into the CaosDB server. If none is provided, the `CAOSDB_USER` - environmental variable is used instead. If that's not defined, - "admin" is used. -- `password::AbstractString="undefined"`: The password with which to - log in into the CaosDB server. If none is provided, the - `CAOSDB_PASSWORD` environmental variable is used instead. If that's - not defined, "caosdb" is used. The default value is "undefined" - rather than an empty string to allow an empty password. -""" -function connect(; - host::AbstractString = "", - port_str::AbstractString = "undefined", - cacert::AbstractString = "", - username::AbstractString = "", - password::AbstractString = "undefined", -) - - if host == "" - - host = CaosDB.Utility.get_env_var("CAOSDB_SERVER_HOST", "localhost") - - end - - if port_str == "undefined" - - port_str = CaosDB.Utility.get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443") - - end - - port = parse(Cint, port_str) - - if cacert == "" - - cacert = CaosDB.Utility.get_env_var("CAOSDB_SERVER_CERT") - - end - - if username == "" - - username = CaosDB.Utility.get_env_var("CAOSDB_USER", "admin") - - end - - if password == "undefined" - - password = CaosDB.Utility.get_env_var("CAOSDB_PASSWORD", "caosdb") - - end - - provider = create_pem_file_certificate_provider(cacert) - authenticator = - CaosDB.Authentication.create_plain_password_authenticator(username, password) - config = create_tls_connection_configuration(host, port, authenticator, provider) - connection = create_connection(config) - print_version_info(connection) - - return connection - -end - -end # Connection +include("Connection.jl") module Entity end diff --git a/src/Connection.jl b/src/Connection.jl new file mode 100644 index 0000000000000000000000000000000000000000..0f8e140a682e1e269b4ee395507b1ce66e54220a --- /dev/null +++ b/src/Connection.jl @@ -0,0 +1,423 @@ +# ** header v3.0 +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> +# Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this program. If not, see +# <https://www.gnu.org/licenses/>. +# +# ** end header +# + +module Connection + +using ..CaosDB + +export connect, connect_manually + +""" +Struct containing the actual connection to a CaosDB server. Meant for +internal use; call a `CaosDB.Connection.create_<connection>` function +to create an connection object from a configuration. +""" +mutable struct _Connection + wrapped_connection::Ptr{Cvoid} + + function _Connection(managed_by_julia::Bool = false) + conn = new() + if managed_by_julia + # Only append a finalizer for this if the object is + # actually managed by Julia and not created and destroyed + # internally by libcaosdb. + function f(t) + ccall( + (:caosdb_connection_delete_connection, CaosDB.library_name), + Cint, + (Ref{_Connection},), + Ref{_Connection}(t), + ) + end + finalizer(f, conn) + end + return conn + end +end + +""" +Struct containing a pointer to the wrapped cpp class providing the +certificate provider. Meant for internal use; call a +`CaosDB.Connection.create_<certificate_provider>` function to create +an certificate-provider object from a configuration. +""" +mutable struct _CertificateProvider + wrapped_certificate_provider::Ptr{Cvoid} + + function _CertificateProvider(managed_by_julia::Bool = false) + prov = new() + if managed_by_julia + # Only append a finalizer for this if the object is + # actually managed by Julia and not created and destroyed + # internally by libcaosdb. + function f(t) + ccall( + (:caosdb_connection_delete_certificate_provider, CaosDB.library_name), + Cint, + (Ref{_CertificateProvider},), + Ref{_CertificateProvider}(t), + ) + end + finalizer(f, prov) + end + return prov + end +end + +""" +Struct containing a pointer to the wrapped cpp class for storing the +connection configuration. Meant for internal use; call a +`CaosDB.Connection.create_<configuration>` function to create +an connection-configuration object from a configuration. +""" +mutable struct _Configuration + wrapped_connection_configuration::Ptr{Cvoid} + + function _Configuration(managed_by_julia::Bool = false) + config = new() + if managed_by_julia + # Only append a finalizer for this if the object is + # actually managed by Julia and not created and destroyed + # internally by libcaosdb. + function f(t) + ccall( + ( + :caosdb_connection_delete_connection_configuration, + CaosDB.library_name, + ), + Cint, + (Ref{_Configuration},), + Ref{_Configuration}(t), + ) + end + finalizer(f, config) + end + return config + end +end + +""" + create_pem_file_certificate_provider(path::AbstractString) + +Return a `_CertificateProvider` for the pem certificate located at +`path`. +""" +function create_pem_file_certificate_provider(path::AbstractString) + + cert_provider = Ref{_CertificateProvider}(_CertificateProvider(true)) + + err_code = ccall( + (:caosdb_connection_create_pem_file_certificate_provider, CaosDB.library_name), + Cint, + (Ref{_CertificateProvider}, Cstring), + cert_provider, + path, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return cert_provider + +end + +""" + create_tls_connection_configuration( + host::AbstractString, + port::Cint, + authenticator::Ref{CaosDB.Authentication._Authenticator}, + provider::Ref{_CertificateProvider} + ) + +Return a TLS connection configuration with authentication. +""" +function create_tls_connection_configuration( + host::AbstractString, + port::Cint, + authenticator::Ref{CaosDB.Authentication._Authenticator}, + provider::Ref{_CertificateProvider}, +) + + config = Ref{_Configuration}(_Configuration(true)) + + err_code = ccall( + (:caosdb_connection_create_tls_connection_configuration, CaosDB.library_name), + Cint, + ( + Ref{_Configuration}, + Cstring, + Cint, + Ref{CaosDB.Authentication._Authenticator}, + Ref{_CertificateProvider}, + ), + config, + host, + port, + authenticator, + provider, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return config + +end + +function create_insecure_connection_configuration(host::AbstractString, port::Cint) + + config = Ref{_Configuration}(_Configuration(true)) + + err_code = ccall( + (:caosdb_connection_create_insecure_connection_configuration, CaosDB.library_name), + Cint, + (Ref{_Configuration}, Cstring, Cint), + config, + host, + port, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return config +end + +""" + create_connection(config::Ref{_Configuration}) + +Return a connection based on the given `config`. +""" +function create_connection(config::Ref{_Configuration}) + + connection = Ref{_Connection}(_Connection(true)) + + err_code = ccall( + (:caosdb_connection_create_connection, CaosDB.library_name), + Cint, + (Ref{_Connection}, Ref{_Configuration}), + connection, + config, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return connection + +end + + +function get_connection(name::AbstractString = "default") + + connection = Ref{_Connection}(_Connection()) + + if name == "default" + err_code = ccall( + ( + :caosdb_connection_connection_manager_get_default_connection, + CaosDB.library_name, + ), + Cint, + (Ref{_Connection},), + connection, + ) + else + err_code = ccall( + (:caosdb_connection_connection_manager_get_connection, CaosDB.library_name), + Cint, + (Ref{_Connection}, Cstring), + connection, + name, + ) + end + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return connection + +end + + +""" + get_version_info(con::Ref{_Connection}) + +Return the version of the CaosDB server that `con` is connected +to. +""" +function get_version_info(con::Ref{_Connection}) + + info = Ref{CaosDB.Info._VersionInfo}(CaosDB.Info._VersionInfo()) + + err_code = ccall( + (:caosdb_connection_get_version_info, CaosDB.library_name), + Cint, + (Ref{CaosDB.Info._VersionInfo}, Ref{_Connection}), + info, + con, + ) + + CaosDB.Exceptions.evaluate_return_code(err_code) + + return info + +end + +""" + print_version_info(con::Ref{_Connection}) + +Retrieve the version info for the CaosDB server `con` is connected to, +and print the version in a nice message. +""" +function print_version_info(con::Ref{_Connection}) + + # Dereference to access the fields + info = get_version_info(con)[] + + major = info.major + minor = info.minor + patch = info.patch + pre_release_str = unsafe_string(info.pre_release) + build_str = unsafe_string(info.build) + + println( + "Connected to a CaosDB server with version $major.$minor.$patch-$pre_release_str-$build_str.", + ) + +end + +""" + function connect_manually([; + host::AbstractString="", + port_str::AbstractString="undefined", + cacert::AbstractString="", + username::AbstractString="", + password::AbstractString="undefined"] + ) + +Return a connection object created for the given `host`:`port` with an +SSL certificate located at `cacert` with the given credentials. + +# Extended help + +!!! info + + Because of type-stability, and since an empty string may be a + valid password, the value of `password`, for which it is fetched + from an environmental variable, is "undefined". This means that if + you absolutely must use "undefined" as your password, you have to + specify it via the `CAOSDB_PASSWORD` variable. + +# Arguments +- `host::AbstractString=""`: The hostname of the CaosDB server. If + none is provided, the `CAOSDB_SERVER_HOST` environmental variable is + used instead. If that's not defined, "localhost" is used. +- `port_str::AbstractString="undefined"`: The port of the CaosDB + server, given as string. If none is provided, the + `CAOSDB_SERVER_GRPC_PORT_HTTPS` environmental variable is used + instead. If that's not defined, "8443" is used. The default value is + "undefined" rather than an empty string because an empty string + could be a valid port, too, i.e. the CaosDB server is available at + `host` without a port. +- `cacert::AbstractString=""`: The path to the SSL certificate of the + CaosDB server. If none is provided, the `CAOSDB_SERVER_CERT` + environmental variable is used instead. +- `username::AbstractString=""`: The username with which to log in + into the CaosDB server. If none is provided, the `CAOSDB_USER` + environmental variable is used instead. If that's not defined, + "admin" is used. +- `password::AbstractString="undefined"`: The password with which to + log in into the CaosDB server. If none is provided, the + `CAOSDB_PASSWORD` environmental variable is used instead. If that's + not defined, "caosdb" is used. The default value is "undefined" + rather than an empty string to allow an empty password. +""" +function connect_manually(; + host::AbstractString = "", + port_str::AbstractString = "undefined", + cacert::AbstractString = "", + username::AbstractString = "", + password::AbstractString = "undefined", +) + + if host == "" + + host = CaosDB.Utility.get_env_var("CAOSDB_SERVER_HOST", "localhost") + + end + + if port_str == "undefined" + + port_str = CaosDB.Utility.get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443") + + end + + port = parse(Cint, port_str) + + if cacert == "" + + cacert = CaosDB.Utility.get_env_var("CAOSDB_SERVER_CERT") + + end + + if username == "" + + username = CaosDB.Utility.get_env_var("CAOSDB_USER", "admin") + + end + + if password == "undefined" + + password = CaosDB.Utility.get_env_var("CAOSDB_PASSWORD", "caosdb") + + end + + provider = create_pem_file_certificate_provider(cacert) + authenticator = + CaosDB.Authentication.create_plain_password_authenticator(username, password) + config = create_tls_connection_configuration(host, port, authenticator, provider) + connection = create_connection(config) + print_version_info(connection) + + return connection + +end + +""" + connect(name::AbstractString="default") + +Create a connection with name `name` from your configuration file, +print the version of the server the connection is established to, and +return the connection object. + +# Arguments + +- name::AbstractString="default": The name of the configuration + defined in your config json that will be used to connect to the + CaosDB server defined therein. Default value is "default". +""" +function connect(name::AbstractString = "default") + conn = get_connection(name) + + print_version_info(conn) + + return conn +end + +end # Connection diff --git a/test/runtests.jl b/test/runtests.jl index 148514976253884a6426d6d858a6d7154bf12dc0..5fa1db168735cfad9532752b8d9d3364074e447b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -23,9 +23,45 @@ using Test using CaosDB -if haskey(ENV, "SHELL") - shell_var = ENV["SHELL"] -else - shell_var = "default" +@testset "CaosDBUnitTests" begin + @testset "TestUtility" begin + if haskey(ENV, "SHELL") + shell_var = ENV["SHELL"] + else + shell_var = "default" + end + @test CaosDB.Utility.get_env_var("SHELL", "default") == shell_var + end + + @testset "TestExceptions" begin + # In case of success, nothing is done + @test CaosDB.Exceptions.evaluate_return_code(Cint(0)) == nothing + + # CaosDBExceptions are thrown for return codes > 0 + @test_throws CaosDB.Exceptions.CaosDBException CaosDB.Exceptions.evaluate_return_code( + Cint(14), + ) + @test_throws CaosDB.Exceptions.GenericCaosDBException CaosDB.Exceptions.evaluate_return_code( + Cint(14), + ) + try + CaosDB.Exceptions.evaluate_return_code(Cint(14)) + # fail if this doesn't throw an error + @test false + catch e + @test isa(e, CaosDB.Exceptions.GenericCaosDBException) + @test e.code == 14 + end + + # Return codes < 0 correspond to unfinished transactions and + # we expect messages to be returned. + @test CaosDB.Exceptions.evaluate_return_code(Cint(-1)) == nothing + @test_logs ( + :info, + CaosDB.Exceptions.CaosDBMessage( + "The transaction is currently being executed.", + Cint(-1), + ), + ) CaosDB.Exceptions.evaluate_return_code(Cint(-1)) + end end -@test CaosDB.Utility.get_env_var("SHELL", "default") == shell_var