Skip to content

Commit 4261c3d

Browse files
authored
[codex] Stabilize Harbor-backed test runs (#235)
* fix(mysql): stabilize Harbor-backed test runs Switch the test suite to a Harbor-managed MySQL container so local and CI testing only assumes Docker availability. Also restore a stable Connector/C SSL default, fix option reads, close load-time prepared statements, and advance multi-result cleanup via nextresult() so the suite stays green on current MariaDB Connector/C releases. Fixes #234 * chore(julia): raise minimum version to 1.10 Julia 1.6 CI cannot resolve Harbor, and Julia 1.10 is the current LTS line as of April 23, 2026. Bump the package compat floor and replace the 1.6 CI lane with 1.10 so the matrix matches the versions we intend to support with the Harbor-backed test harness. * fix(results): restore guarded multi-result advance * fix(results): check more results before free * test(results): use direct connection for multistmt * fix(api): read string option values correctly * test(harbor): require released log wait fix Require Harbor 1.0.3 for tests and switch the MySQL container readiness check back to the intended log-pattern wait now that the stderr capture fix is released.
1 parent bfdcb57 commit 4261c3d

11 files changed

Lines changed: 185 additions & 70 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
fail-fast: false
1313
matrix:
1414
version:
15-
- "1.6"
15+
- "1.10"
1616
- 1 # automatically expands to the latest stable 1.x release of Julia
1717
- nightly
1818
os:
@@ -21,7 +21,7 @@ jobs:
2121
- x64
2222
steps:
2323
- uses: actions/checkout@v5
24-
- run: docker compose up -d
24+
- run: docker info
2525
- uses: julia-actions/setup-julia@v2
2626
with:
2727
version: ${{ matrix.version }}
@@ -50,4 +50,4 @@ jobs:
5050
- run: julia --project=docs docs/make.jl
5151
env:
5252
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53-
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}
53+
DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }}

Project.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
1717
[compat]
1818
DBInterface = "2.5"
1919
DecFP = "0.4.9, 0.4.10, 1"
20+
Harbor = "1.0.3"
2021
MariaDB_Connector_C_jll = "3.1.12"
2122
OpenSSL_jll = "3"
2223
Parsers = "0.3, 1, 2"
2324
Tables = "1"
24-
julia = "1.6"
25+
julia = "1.10"
2526

2627
[extras]
28+
Harbor = "af79dbb9-1a80-47ad-8928-192a4af69376"
29+
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"
2730
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2831

2932
[targets]
30-
test = ["Test"]
33+
test = ["Harbor", "Sockets", "Test"]

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ Package for interfacing with MySQL databases from Julia via the MariaDB C connec
1616
[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://mysql.juliadatabases.org/stable)
1717
[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://mysql.juliadatabases.org/dev)
1818

19-
## Contributing
20-
21-
The tests require a MySQL DB to be running, which is provided by Docker:
22-
23-
```sh
24-
docker compose up -d
25-
julia --project -e 'using Pkg; Pkg.test()'
26-
docker compose down
27-
```
19+
## Contributing
20+
21+
The test suite manages its own temporary MySQL container via Harbor.jl. The only prerequisite is a working Docker daemon:
22+
23+
```sh
24+
julia --project -e 'using Pkg; Pkg.test()'
25+
```

docker-compose.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

src/MySQL.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ function setoptions!(mysql;
128128
ssl_crl::Union{AbstractString, Nothing}=nothing,
129129
ssl_crlpath::Union{AbstractString, Nothing}=nothing,
130130
passphrase::Union{AbstractString, Nothing}=nothing,
131-
ssl_verify_server_cert::Union{Bool, Nothing}=nothing,
131+
ssl_verify_server_cert::Union{Bool, Nothing}=false,
132132
ssl_enforce::Union{Bool, Nothing}=nothing,
133133
ssl_mode::Union{API.mysql_ssl_mode, Nothing}=nothing,
134134
default_auth::Union{AbstractString, Nothing}=nothing,
@@ -279,7 +279,7 @@ Connect to a MySQL database with provided `host`, `user`, and `passwd` positiona
279279
* `ssl_cipher::AbstractString`: Defines a list of permitted ciphers or cipher suites to use for TLS, like `"DHE-RSA-AES256-SHA"`
280280
* `ssl_crl::AbstractString`: Defines a path to a PEM file that should contain one or more revoked X509 certificates to use for TLS. This option requires that you use the absolute path, not a relative path.
281281
* `ssl_crlpath::AbstractString`: Defines a path to a directory that contains one or more PEM files that should each contain one revoked X509 certificate to use for TLS. This option requires that you use the absolute path, not a relative path. The directory specified by this option needs to be run through the openssl rehash command.
282-
* `ssl_verify_server_cert::Bool`: Enables (or disables) server certificate verification.
282+
* `ssl_verify_server_cert::Bool=false`: Enables (or disables) server certificate verification.
283283
* `ssl_enforce::Bool`: Whether to force TLS
284284
* `default_auth::AbstractString`: Default authentication client-side plugin to use.
285285
* `connection_handler::AbstractString`: Specify the name of a connection handler plugin.

src/api/capi.jl

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,21 @@ Zero for success. Nonzero if an error occurred; this occurs for option values th
431431
"""=#
432432
function getoption(mysql::MYSQL, option::mysql_option)
433433
if option in CUINTOPTS
434-
return @checksuccess mysql mysql_get_option_Cuint(mysql.ptr, option, Ref{Cuint}())
434+
ref = Ref{Cuint}()
435+
@checksuccess mysql mysql_get_option_Cuint(mysql.ptr, Int(option), ref)
436+
return ref[]
435437
elseif option in CULONGOPTS
436-
return @checksuccess mysql mysql_get_option_Culong(mysql.ptr, option, Ref{Culong}())
438+
ref = Ref{Culong}()
439+
@checksuccess mysql mysql_get_option_Culong(mysql.ptr, Int(option), ref)
440+
return ref[]
437441
elseif option in BOOLOPTS
438-
return @checksuccess mysql mysql_get_option_Bool(mysql.ptr, option, Ref{Bool}())
442+
ref = Ref{Bool}()
443+
@checksuccess mysql mysql_get_option_Bool(mysql.ptr, Int(option), ref)
444+
return ref[]
439445
else
440-
return @checksuccess mysql mysql_get_option_String(mysql.ptr, option, Ref{String}())
446+
ref = Ref{Ptr{UInt8}}(C_NULL)
447+
@checksuccess mysql mysql_get_option_String(mysql.ptr, Int(option), ref)
448+
return ref[] == C_NULL ? nothing : unsafe_string(ref[])
441449
end
442450
end
443451

src/api/ccalls.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,13 @@ function mysql_get_option_Bool(mysql::Ptr{Cvoid}, option::Integer, arg::Ref{Bool
236236
mysql, option, arg)
237237
end
238238

239+
function mysql_get_option_String(mysql::Ptr{Cvoid}, option::Integer, arg::Ref{Ptr{UInt8}})
240+
return @c(:mysql_get_option,
241+
Cint,
242+
(Ptr{Cvoid}, Cint, Ref{Ptr{UInt8}}),
243+
mysql, option, arg)
244+
end
245+
239246
function mysql_get_option_Cvoid(mysql::Ptr{Cvoid}, option::Integer, arg::Ptr{Cvoid})
240247
return @c(:mysql_get_option,
241248
Cint,

src/execute.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,9 @@ Base.IteratorSize(::Type{<:TextCursors}) = Base.SizeUnknown()
203203
function Base.iterate(cursor::TextCursors{buffered}, first=true) where {buffered}
204204
cursor.cursor.result.ptr == C_NULL && return nothing
205205
if !first
206+
has_more_results = API.moreresults(cursor.cursor.conn.mysql)
206207
finalize(cursor.cursor.result)
207-
if API.moreresults(cursor.cursor.conn.mysql)
208+
if has_more_results
208209
@assert API.nextresult(cursor.cursor.conn.mysql) !== nothing
209210
cursor.cursor.result = buffered ? API.storeresult(cursor.cursor.conn.mysql) : API.useresult(cursor.cursor.conn.mysql)
210211
if buffered
@@ -222,4 +223,4 @@ function Base.iterate(cursor::TextCursors{buffered}, first=true) where {buffered
222223
end
223224

224225
DBInterface.executemultiple(conn::Connection, sql::AbstractString, params=(); kw...) =
225-
TextCursors(DBInterface.execute(conn, sql, params; kw...))
226+
TextCursors(DBInterface.execute(conn, sql, params; kw...))

src/load.jl

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,14 @@ function load(itr, conn::Connection, name::AbstractString="mysql_"*Random.randst
101101
DBInterface.transaction(conn) do
102102
params = chop(repeat("?,", length(sch.names)))
103103
stmt = DBInterface.prepare(conn, "INSERT INTO $name ($(join(sch.names .|> string .|> quoteid,", "))) VALUES ($params)")
104-
for (i, row) in enumerate(rows)
105-
i > limit && break
106-
debug && @info "inserting row $i; $(Tables.Row(row))"
107-
DBInterface.execute(stmt, Tables.Row(row))
104+
try
105+
for (i, row) in enumerate(rows)
106+
i > limit && break
107+
debug && @info "inserting row $i; $(Tables.Row(row))"
108+
DBInterface.execute(stmt, Tables.Row(row))
109+
end
110+
finally
111+
DBInterface.close!(stmt)
108112
end
109113
end
110114

test/my.ini

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)