Ricardo Martinez created CAMEL-24772:
----------------------------------------
Summary: camel-jbang:
OllamaDoctorSupportTest.detectReturnsNotRunningWhenEndpointUnreachable fails on
any machine running Ollama
Key: CAMEL-24772
URL: https://issues.apache.org/jira/browse/CAMEL-24772
Project: Camel
Issue Type: Bug
Components: camel-jbang
Affects Versions: 4.23.0
Reporter: Ricardo Martinez
h2. Problem
{{OllamaDoctorSupportTest.detectReturnsNotRunningWhenEndpointUnreachable}}
fails deterministically on
any developer machine that has a local Ollama instance listening on the default
port
{{localhost:11434}}:
{code}
[ERROR] OllamaDoctorSupportTest.detectReturnsNotRunningWhenEndpointUnreachable
org.opentest4j.AssertionFailedError:
Expecting value to be false but was true
at
OllamaDoctorSupportTest.detectReturnsNotRunningWhenEndpointUnreachable(OllamaDoctorSupportTest.java:49)
{code}
It fails on all three surefire attempts (the module sets
{{rerunFailingTestsCount=2}}), so it is not
flaky — it is a hard, environment-dependent failure. It passes in CI only
because CI hosts have no
Ollama running.
h2. Root cause
The test asserts that an unreachable endpoint yields {{running() == false}}:
{code:java}
LlmClient client =
LlmClient.create().withApiType(LlmClient.ApiType.ollama).withUrl("http://127.0.0.1:1");
OllamaDoctorSupport.Status status = OllamaDoctorSupport.detect(client);
assertThat(status.running()).isFalse();
{code}
The assumption is that {{withUrl(...)}} pins the client to that URL. It does
not.
{{OllamaDoctorSupport.detect(client)}} delegates to
{{LlmClient.detectEndpoint()}}, which is a
*discovery* method with deliberate fallbacks:
{code:java}
public boolean detectEndpoint() {
boolean found;
if (tryExplicitUrl()) { // http://127.0.0.1:1 -> fails,
nothing is listening
found = true;
} else if (apiType != null) {
found = switch (apiType) {
...
case ollama -> tryInfraOllama() || tryDefaultOllama(); // <--
falls back to localhost:11434
};
}
...
}
{code}
So when the explicit URL is unreachable the client falls back to
{{tryInfraOllama()}} (the
{{camel infra run ollama}} PID files) and then {{tryDefaultOllama()}}
({{http://localhost:11434}}).
On a host with Ollama running, {{tryDefaultOllama()}} succeeds and
{{running()}} is correctly
{{true}}.
The production behaviour is right — fallback discovery is the whole point of a
{{camel doctor}}
probe, and the javadoc says so: _"Probes {{camel infra run ollama}} PID files
and the default
{{http://localhost:11434}} endpoint."_ The *test* is what encodes a wrong
assumption. As written it
cannot express "unreachable endpoint means not running" on any host, because
the fallback will always
be consulted.
Note the other tests in the same class are not affected: they start a real
local {{HttpServer}} on an
ephemeral port and assert {{running() == true}} plus a specific {{baseUrl}},
which holds regardless of
host state. Only the negative test is host-dependent.
h2. How to reproduce
{code}
# with Ollama running locally (default port)
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:11434/ # 200
mvn test -pl dsl/camel-jbang/camel-jbang-core -Dtest=OllamaDoctorSupportTest
{code}
Expected: pass. Actual: {{detectReturnsNotRunningWhenEndpointUnreachable}}
fails.
Stopping Ollama makes it pass again.
h2. Suggested fix
Test-only change; no production code needs to change.
Option 1 — skip the assertion when the host itself provides a reachable default
endpoint. Keeps the
CI coverage and matches the class's existing "no mocking framework" style:
{code:java}
@Test
void detectReturnsNotRunningWhenEndpointUnreachable() {
// detectEndpoint() falls back to camel infra / localhost:11434, so this
case is only
// meaningful when the host has no Ollama of its own
assumeFalse(defaultOllamaReachable(), "a local Ollama is running on the
default port");
...
}
{code}
Option 2 — give {{LlmClient}} a package-private seam to disable fallback
discovery, so the negative
path can be asserted unconditionally. More thorough, and makes the explicit-URL
contract testable in
its own right, at the cost of a small production API addition.
Option 1 is probably enough. Either way the intent is worth a comment, since
the next person to read
the test will make the same assumption.
_Claude Code on behalf of [~ricmarti]_
--
This message was sent by Atlassian Jira
(v8.20.10#820010)