test-non-interactive.sh 8.9 KB

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