test-non-interactive.sh 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #!/usr/bin/env bash
  2. #############################################################################
  3. # Non-Interactive Mode Test Script
  4. # Tests the installer behavior when run via pipe (curl | bash)
  5. #
  6. # This test catches bugs like: https://github.com/darrenhinde/OpenAgentsControl/issues/XX
  7. # where interactive prompts fail silently in piped execution.
  8. #############################################################################
  9. set -e
  10. GREEN='\033[0;32m'
  11. RED='\033[0;31m'
  12. YELLOW='\033[1;33m'
  13. CYAN='\033[0;36m'
  14. BOLD='\033[1m'
  15. NC='\033[0m'
  16. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  17. REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
  18. TEST_DIR="/tmp/opencode-noninteractive-test-$$"
  19. PASSED=0
  20. FAILED=0
  21. pass() {
  22. echo -e "${GREEN}✓${NC} $1"
  23. PASSED=$((PASSED + 1))
  24. }
  25. fail() {
  26. echo -e "${RED}✗${NC} $1"
  27. FAILED=$((FAILED + 1))
  28. }
  29. warn() {
  30. echo -e "${YELLOW}⚠${NC} $1"
  31. }
  32. setup() {
  33. rm -rf "$TEST_DIR"
  34. mkdir -p "$TEST_DIR"
  35. }
  36. # shellcheck disable=SC2329
  37. cleanup() {
  38. rm -rf "$TEST_DIR"
  39. }
  40. trap cleanup EXIT
  41. print_header() {
  42. echo -e "${CYAN}${BOLD}"
  43. echo "╔════════════════════════════════════════════════════════════════╗"
  44. echo "║ Non-Interactive Mode Test Suite ║"
  45. echo "╚════════════════════════════════════════════════════════════════╝"
  46. echo -e "${NC}"
  47. }
  48. run_with_timeout() {
  49. local duration=$1
  50. shift
  51. if command -v timeout &> /dev/null; then
  52. timeout "$duration" "$@"
  53. elif command -v gtimeout &> /dev/null; then
  54. gtimeout "$duration" "$@"
  55. else
  56. # Fallback: run without timeout
  57. "$@"
  58. fi
  59. }
  60. #############################################################################
  61. # Test 1: Fresh install with piped input (simulates curl | bash)
  62. #############################################################################
  63. test_fresh_install_piped() {
  64. echo -e "\n${BOLD}Test 1: Fresh Install via Pipe${NC}"
  65. local install_dir="$TEST_DIR/fresh-install/.opencode"
  66. if echo "" | bash "$REPO_ROOT/install.sh" essential --install-dir="$install_dir" 2>&1 | grep -q "Installation complete"; then
  67. if [ -d "$install_dir" ]; then
  68. pass "Fresh install completed successfully via pipe"
  69. if [ -f "$install_dir/config/agent-metadata.json" ]; then
  70. pass "Fresh piped install included agent metadata config"
  71. else
  72. fail "Fresh piped install missing agent metadata config"
  73. fi
  74. else
  75. fail "Install reported success but directory not created"
  76. fi
  77. else
  78. fail "Fresh install via pipe failed"
  79. fi
  80. }
  81. #############################################################################
  82. # Test 2: Install with existing files (collision scenario)
  83. #############################################################################
  84. test_collision_non_interactive() {
  85. echo -e "\n${BOLD}Test 2: Collision Handling in Non-Interactive Mode${NC}"
  86. local install_dir="$TEST_DIR/collision-test/.opencode"
  87. mkdir -p "$install_dir/agent/core"
  88. echo "existing content" > "$install_dir/agent/core/openagent.md"
  89. local output
  90. output=$(echo "" | bash "$REPO_ROOT/install.sh" essential --install-dir="$install_dir" 2>&1)
  91. if echo "$output" | grep -q "Installation cancelled by user"; then
  92. fail "BUG DETECTED: Non-interactive mode cancelled due to collision prompt"
  93. echo " This is the exact bug we're testing for!"
  94. return 1
  95. fi
  96. if echo "$output" | grep -q "skip.*strategy\|Skipped existing"; then
  97. pass "Collision handled correctly - used skip strategy"
  98. elif echo "$output" | grep -q "Installation complete"; then
  99. pass "Installation completed (no collision or handled silently)"
  100. else
  101. fail "Unexpected behavior during collision handling"
  102. echo " Output: $output"
  103. fi
  104. local original_content
  105. original_content=$(cat "$install_dir/agent/core/openagent.md" 2>/dev/null || echo "")
  106. if [ "$original_content" = "existing content" ]; then
  107. pass "Existing file preserved (skip strategy worked)"
  108. else
  109. warn "Existing file was overwritten (may be intentional in some modes)"
  110. fi
  111. }
  112. #############################################################################
  113. # Test 3: Essential profile in non-interactive mode (CI tests all profiles)
  114. #############################################################################
  115. test_profile_non_interactive() {
  116. echo -e "\n${BOLD}Test 3: Essential Profile Non-Interactive${NC}"
  117. local install_dir="$TEST_DIR/profile-essential/.opencode"
  118. local output
  119. output=$(echo "" | run_with_timeout 60 bash "$REPO_ROOT/install.sh" essential --install-dir="$install_dir" 2>&1) || true
  120. if echo "$output" | grep -q "Installation complete"; then
  121. pass "Profile 'essential' installed successfully"
  122. elif echo "$output" | grep -q "Installation cancelled"; then
  123. fail "Profile 'essential' failed - cancelled unexpectedly"
  124. else
  125. fail "Profile 'essential' had unexpected output"
  126. fi
  127. }
  128. #############################################################################
  129. # Test 4: Simulated curl | bash execution
  130. #############################################################################
  131. test_simulated_curl_pipe() {
  132. echo -e "\n${BOLD}Test 4: Simulated curl | bash Execution${NC}"
  133. local install_dir="$TEST_DIR/curl-sim/.opencode"
  134. cat "$REPO_ROOT/install.sh" | bash -s essential --install-dir="$install_dir" > "$TEST_DIR/curl-output.txt" 2>&1
  135. if grep -q "Installation complete\|Installed:" "$TEST_DIR/curl-output.txt"; then
  136. pass "Simulated 'curl | bash -s essential' worked"
  137. elif grep -q "cancelled" "$TEST_DIR/curl-output.txt"; then
  138. fail "Simulated curl pipe was cancelled unexpectedly"
  139. else
  140. fail "Simulated curl pipe had unexpected result"
  141. cat "$TEST_DIR/curl-output.txt"
  142. fi
  143. }
  144. #############################################################################
  145. # Test 5: stdin detection
  146. #############################################################################
  147. test_stdin_detection() {
  148. echo -e "\n${BOLD}Test 5: stdin Detection${NC}"
  149. if [ -t 0 ]; then
  150. pass "Running in terminal (stdin is TTY)"
  151. else
  152. warn "Running in non-interactive mode (stdin is not TTY)"
  153. fi
  154. local in_pipe
  155. in_pipe=$(echo "" | bash -c '[ -t 0 ] && echo "tty" || echo "pipe"')
  156. if [ "$in_pipe" = "pipe" ]; then
  157. pass "Pipe detection works correctly"
  158. else
  159. fail "Pipe detection failed"
  160. fi
  161. }
  162. #############################################################################
  163. # Test 6: NON_INTERACTIVE flag is set correctly
  164. #############################################################################
  165. test_non_interactive_flag() {
  166. echo -e "\n${BOLD}Test 6: NON_INTERACTIVE Flag Detection${NC}"
  167. local output
  168. output=$(bash "$REPO_ROOT/install.sh" essential --help 2>&1 | head -20)
  169. if echo "$output" | grep -q "Usage:"; then
  170. pass "Script executes and shows help"
  171. else
  172. fail "Script failed to show help"
  173. fi
  174. output=$(echo "" | bash "$REPO_ROOT/install.sh" essential --install-dir="$TEST_DIR/flag-test" 2>&1)
  175. if echo "$output" | grep -q "non-interactive\|automatically"; then
  176. pass "Non-interactive mode detected and reported"
  177. else
  178. pass "Installation proceeded (flag working silently)"
  179. fi
  180. }
  181. #############################################################################
  182. # Test 7: Error handling in non-interactive mode
  183. #############################################################################
  184. test_error_handling_non_interactive() {
  185. echo -e "\n${BOLD}Test 7: Error Handling in Non-Interactive Mode${NC}"
  186. local output
  187. output=$(echo "" | bash "$REPO_ROOT/install.sh" invalid_profile 2>&1) || true
  188. if echo "$output" | grep -q "Unknown option\|Invalid\|Error"; then
  189. pass "Invalid profile rejected with clear error"
  190. else
  191. fail "Invalid profile should produce error message"
  192. fi
  193. }
  194. #############################################################################
  195. # Main
  196. #############################################################################
  197. main() {
  198. print_header
  199. echo "Repository: $REPO_ROOT"
  200. echo "Test directory: $TEST_DIR"
  201. echo ""
  202. setup
  203. test_fresh_install_piped
  204. test_collision_non_interactive
  205. test_profile_non_interactive
  206. test_simulated_curl_pipe
  207. test_stdin_detection
  208. test_non_interactive_flag
  209. test_error_handling_non_interactive
  210. echo ""
  211. echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
  212. echo -e "${BOLD}Test Summary${NC}"
  213. echo -e " ${GREEN}Passed: $PASSED${NC}"
  214. echo -e " ${RED}Failed: $FAILED${NC}"
  215. echo -e "${BOLD}═══════════════════════════════════════════════════════════════${NC}"
  216. if [ $FAILED -gt 0 ]; then
  217. echo -e "\n${RED}Some tests failed!${NC}"
  218. exit 1
  219. else
  220. echo -e "\n${GREEN}All tests passed!${NC}"
  221. exit 0
  222. fi
  223. }
  224. main "$@"