From 074a2b1f5f1891f050f8ec3033c837555f1adef2 Mon Sep 17 00:00:00 2001 From: mike Date: Thu, 11 Dec 2025 08:27:03 +0100 Subject: [PATCH] update --- Dockerfile.test | 34 ----------- finish.sh | 50 ++++++++++------ run_tests.sh | 3 + tests/test_finish.sh | 23 ++++++++ tests/test_finish_ollama.sh | 112 ++++++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+), 53 deletions(-) delete mode 100644 Dockerfile.test create mode 100755 tests/test_finish_ollama.sh diff --git a/Dockerfile.test b/Dockerfile.test deleted file mode 100644 index 5d05695..0000000 --- a/Dockerfile.test +++ /dev/null @@ -1,34 +0,0 @@ -# finish.sh Test Container -FROM ubuntu:22.04 - -LABEL maintainer="finish contributors" -LABEL description="Test environment for finish.sh" - -ENV DEBIAN_FRONTEND=noninteractive - -# Install dependencies including BATS for testing -RUN apt-get update && \ - apt-get install -y \ - bash \ - bash-completion \ - curl \ - wget \ - jq \ - bc \ - vim \ - git \ - bats \ - && apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /opt/finish - -# Copy all files -COPY . . - -# Make scripts executable -RUN chmod +x finish.sh - -# Run tests by default -ENTRYPOINT ["bats"] -CMD ["tests"] diff --git a/finish.sh b/finish.sh index 818c0b5..a48577b 100644 --- a/finish.sh +++ b/finish.sh @@ -259,16 +259,21 @@ log_request() { openai_completion() { local content status_code response_body default_user_input user_input api_key payload endpoint timeout attempt max_attempts local log_file debug_log + + # Ensure configuration (provider, endpoint, etc.) is loaded before checks + acsh_load_config + + log_file=${ACSH_LOG_FILE:-"$HOME/.finish/finish.log"} + debug_log="$HOME/.finish/debug.log" endpoint=${ACSH_ENDPOINT:-"http://plato.lan:1234/v1/chat/completions"} timeout=${ACSH_TIMEOUT:-30} default_user_input="Write two to six most likely commands given the provided information" user_input=${*:-$default_user_input} - log_file=${ACSH_LOG_FILE:-"$HOME/.finish/finish.log"} - debug_log="$HOME/.finish/debug.log" + # Only check for API key if not using local providers that don't require it if [[ -z "$ACSH_ACTIVE_API_KEY" && ${ACSH_PROVIDER^^} != "OLLAMA" && ${ACSH_PROVIDER^^} != "LMSTUDIO" ]]; then echo_error "ACSH_ACTIVE_API_KEY not set. Please set it with: export ${ACSH_PROVIDER^^}_API_KEY=" - return + return 1 fi api_key="${ACSH_ACTIVE_API_KEY}" payload=$(_build_payload "$user_input") @@ -300,9 +305,16 @@ openai_completion() { if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then \curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" --data "$payload" -N > "$temp_file" else - \curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ - -H "Content-Type: application/json" \ - -d "$payload" -N > "$temp_file" + if [[ -n "$api_key" ]]; then + \curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $api_key" \ + -d "$payload" -N > "$temp_file" + else + \curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ + -H "Content-Type: application/json" \ + -d "$payload" -N > "$temp_file" + fi fi status_code=$(tail -n1 "$temp_file") @@ -330,9 +342,16 @@ openai_completion() { if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" --data "$payload") else - response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ - -H "Content-Type: application/json" \ - -d "$payload") + if [[ -n "$api_key" ]]; then + response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $api_key" \ + -d "$payload") + else + response=$(\curl -s -m "$timeout" -w "\n%{http_code}" "$endpoint" \ + -H "Content-Type: application/json" \ + -d "$payload") + fi fi status_code=$(echo "$response" | tail -n1) response_body=$(echo "$response" | sed '$d') @@ -362,8 +381,8 @@ openai_completion() { 500) echo_error "Internal Server Error: An unexpected error occurred on the API server." ;; *) echo_error "Unknown Error: Unexpected status code $status_code received. Response: $response_body" ;; esac - return - fi + return 1 +fi if [[ "${ACSH_PROVIDER^^}" == "OLLAMA" ]]; then content=$(echo "$response_body" | jq -r '.message.content') @@ -393,7 +412,7 @@ openai_completion() { if [[ -z "$completions" ]]; then echo_error "Failed to parse completions from API response. Check $debug_log for details." - return + return 1 fi echo -n "$completions" @@ -446,13 +465,6 @@ _finishsh() { if [[ ${#COMPREPLY[@]} -eq 0 && $COMP_TYPE -eq 63 ]]; then local completions user_input user_input_hash acsh_load_config - if [[ -z "$ACSH_ACTIVE_API_KEY" && ${ACSH_PROVIDER^^} != "OLLAMA" && ${ACSH_PROVIDER^^} != "LMSTUDIO" ]]; then - local provider_key="${ACSH_PROVIDER}_API_KEY" - provider_key=$(echo "$provider_key" | tr '[:lower:]' '[:upper:]') - echo_error "${provider_key} is not set. Please set it using: export ${provider_key}= or disable finish via: finish disable" - echo - return - fi if [[ -n "${COMP_WORDS[*]}" ]]; then command="${COMP_WORDS[0]}" if [[ -n "$COMP_CWORD" && "$COMP_CWORD" -lt "${#COMP_WORDS[@]}" ]]; then diff --git a/run_tests.sh b/run_tests.sh index bc39c9e..6a9a57c 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -7,3 +7,6 @@ cd "$SCRIPT_DIR" # Execute the tests bash ./tests/test_finish.sh + +# Also try the local Ollama end-to-end test (skips if Ollama not running) +bash ./tests/test_finish_ollama.sh diff --git a/tests/test_finish.sh b/tests/test_finish.sh index d32ae14..ab53ded 100755 --- a/tests/test_finish.sh +++ b/tests/test_finish.sh @@ -16,6 +16,28 @@ assert_nonempty() { assert_contains() { if [[ ! "$1" =~ $2 ]]; then fail "$3"; fi } + +# Ensure output does not contain any of the common error phrases. +assert_no_common_errors() { + local output="$1" + local -a patterns=( + "ACSH_ACTIVE_API_KEY not set" + "Bad Request" + "Unauthorized" + "Too Many Requests" + "Internal Server Error" + "Unknown Error" + "Failed to parse completions" + "SyntaxError" + "ERROR:" + ) + for pat in "${patterns[@]}"; do + if grep -qE "$pat" <<<"$output"; then + printf "Test failed: output contains error pattern '%s'\nFull output follows:\n%s\n" "$pat" "$output" + exit 1 + fi + done +} # -------------------------------- echo "=== SETUP ===" @@ -50,6 +72,7 @@ pass "finish config contains lmstudio" out=$(finish command "ls # show largest files" 2>&1) ; code=$? assert_ok $code "finish command did not exit 0" assert_nonempty "$out" "finish command returned empty output" +assert_no_common_errors "$out" pass "finish command executed and returned output" # ------------------------------- CLEANUP -------------------------------- diff --git a/tests/test_finish_ollama.sh b/tests/test_finish_ollama.sh new file mode 100755 index 0000000..20afc27 --- /dev/null +++ b/tests/test_finish_ollama.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ----- tiny test framework ----- +pass() { printf "✔ %s\n" "$1"; } +fail() { printf "✘ %s\n" "$1"; exit 1; } + +assert_ok() { + if [[ $1 -ne 0 ]]; then fail "$2"; fi +} + +assert_nonempty() { + if [[ -z "$1" ]]; then fail "$2"; fi +} + +assert_contains() { + if [[ ! "$1" =~ $2 ]]; then fail "$3"; fi +} + +# Ensure output does not contain any of the common error phrases. +assert_no_common_errors() { + local output="$1" + local -a patterns=( + "ACSH_ACTIVE_API_KEY not set" + "Bad Request" + "Unauthorized" + "Too Many Requests" + "Internal Server Error" + "Unknown Error" + "Failed to parse completions" + "SyntaxError" + "ERROR:" + ) + for pat in "${patterns[@]}"; do + if grep -qE "$pat" <<<"$output"; then + printf "Test failed: output contains error pattern '%s'\nFull output follows:\n%s\n" "$pat" "$output" + exit 1 + fi + done +} +# -------------------------------- + +echo "=== OLLAMA TEST: SETUP ===" + +# Always run from the repo root for predictable paths +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR/.." + +# Install finish (adds to PATH and shell rc files) +bash ./docs/install.sh main + +# Load the updated shell rc so `finish` is available on PATH in this session +if [[ -f ~/.bashrc ]]; then + # shellcheck disable=SC1090 + source ~/.bashrc || true +fi + +# ---- Check prerequisites for local Ollama ---- +OLLAMA_URL=${OLLAMA_URL:-"http://localhost:11434"} + +echo "Checking Ollama at $OLLAMA_URL ..." +if ! curl -fsS --max-time 2 "$OLLAMA_URL/api/version" >/dev/null 2>&1; then + echo "SKIP: Ollama is not reachable at $OLLAMA_URL. Start it with: 'ollama serve' and ensure a model is pulled (e.g., 'ollama pull llama3')." + exit 0 +fi + +# Try to discover an installed model; prefer the first listed +MODEL=$(curl -fsS "$OLLAMA_URL/api/tags" | jq -r '.models[0].name // empty' || echo "") +if [[ -z "$MODEL" ]]; then + echo "SKIP: No local Ollama models found. Pull one first, e.g.: 'ollama pull llama3:latest'" + exit 0 +fi + +echo "Using Ollama model: $MODEL" + +# -------------------------------- TESTS -------------------------------- + +# 1) configure finish to use local Ollama +finish config set provider ollama +finish config set endpoint "$OLLAMA_URL/api/chat" +finish config set model "$MODEL" + +# 2) which finish should return something +out=$(which finish 2>&1) ; code=$? +assert_ok $code "which finish should exit 0" +assert_nonempty "$out" "which finish returned empty output" +pass "which finish returns path" + +# 3) finish output should contain 'finish.sh' +out=$(finish 2>&1) ; code=$? +assert_ok $code "finish should exit 0" +assert_contains "$out" "finish\.sh" "finish output does not contain finish.sh" +pass "finish outputs reference to finish.sh" + +# 4) config should mention ollama +out=$(finish config 2>&1) ; code=$? +assert_ok $code "finish config should exit 0" +assert_contains "$out" "ollama" "finish config missing ollama provider" +pass "finish config contains ollama" + +# 5) finish command should run and return output +out=$(finish command "ls # show largest files" 2>&1) ; code=$? +assert_ok $code "finish command did not exit 0" +assert_nonempty "$out" "finish command returned empty output" +assert_no_common_errors "$out" +pass "finish command executed and returned output (ollama)" + +# ------------------------------- CLEANUP -------------------------------- +echo "=== OLLAMA TEST: CLEANUP ===" +finish remove -y || true + +echo "Ollama test passed."