diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 0000000..893ae9b --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,293 @@ +name: E2E Tests + +on: + workflow_dispatch: + inputs: + release_tag: + description: 'GitHub release tag to test (e.g., v0.4.2)' + required: true + type: string + test_channel: + description: 'TX3 channel to test' + required: false + default: 'stable' + type: choice + options: + - stable + - nightly + - beta + +env: + CARGO_TERM_COLOR: always + +jobs: + # Download tx3up binaries from GitHub releases + download-binaries: + name: Download tx3up (${{ matrix.os }}-${{ matrix.arch }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + include: + # Ubuntu Intel + - os: ubuntu + arch: intel + asset_pattern: "*x86_64-unknown-linux-gnu*" + artifact_name: tx3up-ubuntu-intel + + # Ubuntu ARM + - os: ubuntu + arch: arm + asset_pattern: "*aarch64-unknown-linux-gnu*" + artifact_name: tx3up-ubuntu-arm + + # macOS Intel + - os: mac + arch: intel + asset_pattern: "*x86_64-apple-darwin*" + artifact_name: tx3up-mac-intel + + # macOS ARM + - os: mac + arch: arm + asset_pattern: "*aarch64-apple-darwin*" + artifact_name: tx3up-mac-arm + + steps: + - name: Download release asset + env: + GH_TOKEN: ${{ github.token }} + run: | + echo "Downloading tx3up ${{ inputs.release_tag }} for ${{ matrix.os }}-${{ matrix.arch }}" + + # Create target directory + mkdir -p target/release + + # List available assets first + echo "Available assets for ${{ inputs.release_tag }}:" + gh release view ${{ inputs.release_tag }} --repo ${{ github.repository }} --json assets --jq '.assets[].name' + + # Download the asset using GitHub CLI + echo "Downloading assets matching pattern: ${{ matrix.asset_pattern }}" + gh release download ${{ inputs.release_tag }} \ + --repo ${{ github.repository }} \ + --pattern "${{ matrix.asset_pattern }}" \ + --dir target/release/ + + # List what was downloaded + echo "Downloaded files:" + ls -la target/release/ + + # Find the downloaded file and extract if it's an archive + downloaded_file=$(find target/release -type f \( -name "*.tar.gz" -o -name "*.tar.xz" -o -name "*.zip" -o -name "*${{ matrix.os }}*${{ matrix.arch }}*" -o -name "*$(echo "${{ matrix.asset_pattern }}" | tr -d '*')*" \) | head -1) + + if [[ -z "$downloaded_file" ]]; then + echo "Error: No suitable file found for ${{ matrix.os }}-${{ matrix.arch }}" + echo "Available files:" + ls -la target/release/ + exit 1 + fi + + echo "Processing file: $downloaded_file" + + # Extract archives or handle direct binaries + if [[ "$downloaded_file" == *.tar.gz ]]; then + echo "Extracting tar.gz archive..." + tar -xzf "$downloaded_file" -C target/release/ + rm "$downloaded_file" + elif [[ "$downloaded_file" == *.tar.xz ]]; then + echo "Extracting tar.xz archive..." + tar -xJf "$downloaded_file" -C target/release/ + rm "$downloaded_file" + elif [[ "$downloaded_file" == *.zip ]]; then + echo "Extracting zip archive..." + unzip "$downloaded_file" -d target/release/ + rm "$downloaded_file" + else + echo "File appears to be a direct binary" + fi + + # Find the tx3up binary + tx3up_binary=$(find target/release -name "tx3up" -type f -executable 2>/dev/null | head -1) + if [[ -z "$tx3up_binary" ]]; then + # Try without executable check (some extracted files might not have exec bit set) + tx3up_binary=$(find target/release -name "tx3up" -type f | head -1) + fi + + if [[ -z "$tx3up_binary" ]]; then + echo "Error: tx3up binary not found after extraction" + echo "Contents after extraction/download:" + find target/release -type f -exec ls -la {} \; + exit 1 + fi + + echo "Found tx3up binary at: $tx3up_binary" + + # Move binary to standard location and make executable + if [[ "$tx3up_binary" != "target/release/tx3up" ]]; then + mv "$tx3up_binary" target/release/tx3up + fi + chmod +x target/release/tx3up + + echo "Successfully prepared tx3up binary" + + - name: Verify binary + run: | + ls -la target/release/tx3up + file target/release/tx3up + ./target/release/tx3up --version || echo "Version check failed, but binary exists" + + - name: Upload binary artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact_name }} + path: target/release/tx3up + retention-days: 1 + + # Run E2E tests using the downloaded binaries + e2e-tests: + name: E2E Tests (${{ matrix.os }}-${{ matrix.arch }}, ${{ matrix.test }}) + runs-on: ${{ matrix.runner }} + needs: download-binaries + + strategy: + fail-fast: false + matrix: + include: + # Ubuntu Intel tests + - os: ubuntu + arch: intel + runner: ubuntu-latest + artifact_name: tx3up-ubuntu-intel + test: fresh_install + - os: ubuntu + arch: intel + runner: ubuntu-latest + artifact_name: tx3up-ubuntu-intel + test: update_install + + # Ubuntu ARM tests + - os: ubuntu + arch: arm + runner: ubuntu-latest + artifact_name: tx3up-ubuntu-arm + test: fresh_install + - os: ubuntu + arch: arm + runner: ubuntu-latest + artifact_name: tx3up-ubuntu-arm + test: update_install + + # macOS Intel tests + - os: mac + arch: intel + runner: macos-13 + artifact_name: tx3up-mac-intel + test: fresh_install + - os: mac + arch: intel + runner: macos-13 + artifact_name: tx3up-mac-intel + test: update_install + + # macOS ARM tests + - os: mac + arch: arm + runner: macos-latest + artifact_name: tx3up-mac-arm + test: fresh_install + - os: mac + arch: arm + runner: macos-latest + artifact_name: tx3up-mac-arm + test: update_install + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download tx3up binary + uses: actions/download-artifact@v4 + with: + name: ${{ matrix.artifact_name }} + path: target/release/ + + - name: Make binary executable + run: chmod +x target/release/tx3up + + - name: Verify binary + run: | + ls -la target/release/tx3up + file target/release/tx3up + + - name: Install jq (for JSON validation) + run: | + if [[ "${{ matrix.os }}" == "ubuntu" ]]; then + sudo apt-get update && sudo apt-get install -y jq + elif [[ "${{ matrix.os }}" == "mac" ]]; then + brew install jq + fi + + - name: Run E2E test - ${{ matrix.test }} + run: | + echo "Running ${{ matrix.test }} test on ${{ matrix.os }}-${{ matrix.arch }}" + echo "Testing release: ${{ inputs.release_tag }}" + echo "Testing channel: ${{ inputs.test_channel }}" + ./tests/e2e/${{ matrix.test }}.sh + env: + # Use a unique root directory for each test run + TX3_ROOT_DIR: ${{ github.workspace }}/test-root-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.test }} + TX3_CHANNEL: ${{ inputs.test_channel }} + + - name: Upload test artifacts on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-artifacts-${{ matrix.os }}-${{ matrix.arch }}-${{ matrix.test }} + path: | + ${{ github.workspace }}/test-root-*/ + target/release/tx3up + retention-days: 7 + + - name: Display test summary + if: always() + run: | + echo "## E2E Test Summary" >> $GITHUB_STEP_SUMMARY + echo "- **Release**: ${{ inputs.release_tag }}" >> $GITHUB_STEP_SUMMARY + echo "- **OS**: ${{ matrix.os }}" >> $GITHUB_STEP_SUMMARY + echo "- **Architecture**: ${{ matrix.arch }}" >> $GITHUB_STEP_SUMMARY + echo "- **Test**: ${{ matrix.test }}" >> $GITHUB_STEP_SUMMARY + echo "- **Channel**: ${{ inputs.test_channel }}" >> $GITHUB_STEP_SUMMARY + echo "- **Runner**: ${{ matrix.runner }}" >> $GITHUB_STEP_SUMMARY + if [[ "${{ job.status }}" == "success" ]]; then + echo "- **Result**: ✅ PASSED" >> $GITHUB_STEP_SUMMARY + else + echo "- **Result**: ❌ FAILED" >> $GITHUB_STEP_SUMMARY + fi + + # Summary job that depends on all matrix jobs + e2e-summary: + name: E2E Tests Summary + runs-on: ubuntu-latest + needs: [download-binaries, e2e-tests] + if: always() + + steps: + - name: Check test results + run: | + echo "## Overall E2E Test Results" >> $GITHUB_STEP_SUMMARY + echo "**Tested Release**: ${{ inputs.release_tag }}" >> $GITHUB_STEP_SUMMARY + echo "**Tested Channel**: ${{ inputs.test_channel }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ needs.e2e-tests.result }}" == "success" ]]; then + echo "🎉 All E2E tests passed!" >> $GITHUB_STEP_SUMMARY + echo "📦 Downloaded binaries for all platforms successfully" >> $GITHUB_STEP_SUMMARY + exit 0 + else + echo "❌ Some tests failed. Check individual job results for details." >> $GITHUB_STEP_SUMMARY + if [[ "${{ needs.download-binaries.result }}" != "success" ]]; then + echo "📥 Binary download stage failed" >> $GITHUB_STEP_SUMMARY + fi + exit 1 + fi \ No newline at end of file diff --git a/README.md b/README.md index efed464..ad4c248 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,110 @@ # up The Tx3 toolchain installer + +## Running E2E Tests Locally + +The project includes end-to-end tests that verify the `tx3up` installer functionality. These tests can be run locally to ensure the installer works correctly in your environment. + +### Prerequisites + +1. **Build the binary**: First, build the release version of `tx3up`: + ```bash + cargo build --release + ``` + +2. **Install jq** (optional, for enhanced JSON validation): + ```bash + # On Ubuntu/Debian + sudo apt-get install jq + + # On macOS + brew install jq + ``` + +### Available Tests + +- **`fresh_install.sh`**: Tests a clean installation of the toolchain +- **`update_install.sh`**: Tests updating an existing installation + +### Running Tests + +#### Run Individual Tests + +```bash +# Run fresh install test +./tests/e2e/fresh_install.sh + +# Run update install test +./tests/e2e/update_install.sh +``` + +#### Run All Tests + +```bash +# Run all e2e tests +for test in tests/e2e/*.sh; do + echo "Running $test..." + "$test" +done +``` + +#### Custom Test Configuration + +You can customize the test behavior using environment variables: + +```bash +# Use a specific installation directory +export TX3_ROOT_DIR="/tmp/my_tx3_test" +./tests/e2e/fresh_install.sh + +# Test with a different channel (default is "stable") +export TX3_CHANNEL="nightly" +./tests/e2e/fresh_install.sh + +# Combine both parameters +export TX3_ROOT_DIR="/tmp/my_tx3_test" +export TX3_CHANNEL="beta" +./tests/e2e/update_install.sh + +# The test will automatically clean up after itself +``` + +### Test Output + +Each test provides colored output showing: +- ✅ Green: Successful operations +- ❌ Red: Failed operations +- ⚠️ Yellow: Warnings or informational messages + +The tests will: +1. Create a temporary installation directory +2. Run the installer with the test configuration +3. Verify the installation artifacts +4. Clean up temporary files automatically + +### CI/CD + +The E2E tests can be run manually in GitHub Actions using the "E2E Tests" workflow: + +**Manual Workflow Trigger** +- Navigate to Actions → E2E Tests → Run workflow +- Specify the GitHub release tag to test (e.g., `v0.4.2`) +- Choose the TX3 channel to test (`stable`, `nightly`, or `beta`) + +**How it works:** + +**Stage 1: Download Binaries** (4 jobs) +- Downloads release binaries from GitHub releases for each platform: + - Ubuntu Intel (x86_64-unknown-linux-gnu) + - Ubuntu ARM (aarch64-unknown-linux-gnu) + - macOS Intel (x86_64-apple-darwin) + - macOS ARM (aarch64-apple-darwin) + +**Stage 2: Run Tests** (8 jobs) +- Downloads the appropriate binary for each platform +- Runs both `fresh_install` and `update_install` tests +- Tests against the specified channel + +This approach tests actual released binaries rather than building from source, ensuring the published artifacts work correctly. + +Check the `.github/workflows/e2e.yml` file for the complete workflow configuration. diff --git a/tests/e2e/fresh_install.sh b/tests/e2e/fresh_install.sh new file mode 100755 index 0000000..9a551cc --- /dev/null +++ b/tests/e2e/fresh_install.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +# Fresh Install E2E Test for tx3up +# This test verifies that tx3up can perform a clean installation of the toolchain. + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Test configuration +TEST_NAME="fresh_install" +TEMP_DIR=$(mktemp -d) +export TX3_ROOT_DIR="$TEMP_DIR/tx3_test" +export TX3_CHANNEL="${TX3_CHANNEL:-stable}" + +echo -e "${YELLOW}Starting $TEST_NAME test...${NC}" +echo "TX3_ROOT_DIR: $TX3_ROOT_DIR" +echo "TX3_CHANNEL: $TX3_CHANNEL" +echo "Temp directory: $TEMP_DIR" + +# Cleanup function +cleanup() { + echo -e "${YELLOW}Cleaning up test artifacts...${NC}" + rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + +# Function to check if a file exists and is executable +check_executable() { + local file_path="$1" + local description="$2" + + if [[ -f "$file_path" && -x "$file_path" ]]; then + echo -e "${GREEN}✓ $description found and executable: $file_path${NC}" + return 0 + else + echo -e "${RED}✗ $description not found or not executable: $file_path${NC}" + return 1 + fi +} + +# Function to check if a directory exists +check_directory() { + local dir_path="$1" + local description="$2" + + if [[ -d "$dir_path" ]]; then + echo -e "${GREEN}✓ $description exists: $dir_path${NC}" + return 0 + else + echo -e "${RED}✗ $description does not exist: $dir_path${NC}" + return 1 + fi +} + +# Function to check if a file exists +check_file() { + local file_path="$1" + local description="$2" + + if [[ -f "$file_path" ]]; then + echo -e "${GREEN}✓ $description exists: $file_path${NC}" + return 0 + else + echo -e "${RED}✗ $description does not exist: $file_path${NC}" + return 1 + fi +} + +# Main test execution +main() { + echo -e "${YELLOW}Step 1: Verifying clean state${NC}" + + # Ensure the root directory doesn't exist initially + if [[ -e "$TX3_ROOT_DIR" ]]; then + echo -e "${RED}✗ TX3_ROOT_DIR already exists, not a fresh install${NC}" + exit 1 + fi + echo -e "${GREEN}✓ Clean state verified - TX3_ROOT_DIR does not exist${NC}" + + echo -e "${YELLOW}Step 2: Running tx3up install${NC}" + + # Run the installer + if ! ./target/release/tx3up; then + echo -e "${RED}✗ tx3up installation failed${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ tx3up installation completed${NC}" + + echo -e "${YELLOW}Step 3: Verifying installation artifacts${NC}" + + # Check if the root directory was created + check_directory "$TX3_ROOT_DIR" "TX3 root directory" + + # Check if the channel directory exists + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL" "Channel directory ($TX3_CHANNEL)" + + # Check if the bin directory exists + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL/bin" "Binary directory" + + # Check if manifest file exists + check_file "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json" "Manifest file" + + echo -e "${YELLOW}Step 4: Verifying installation contents${NC}" + + # List the contents of the installation for debugging + echo "Installation directory contents:" + find "$TX3_ROOT_DIR" -type f -exec ls -la {} \; 2>/dev/null || true + + # Check if at least one binary was installed + bin_count=$(find "$TX3_ROOT_DIR/$TX3_CHANNEL/bin" -type f -executable 2>/dev/null | wc -l) + if [[ $bin_count -gt 0 ]]; then + echo -e "${GREEN}✓ Found $bin_count executable binaries in bin directory${NC}" + else + echo -e "${RED}✗ No executable binaries found in bin directory${NC}" + exit 1 + fi + + echo -e "${YELLOW}Step 5: Testing manifest file${NC}" + + # Verify the manifest file is valid JSON + if command -v jq >/dev/null 2>&1; then + if jq empty "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json" 2>/dev/null; then + echo -e "${GREEN}✓ Manifest file is valid JSON${NC}" + else + echo -e "${RED}✗ Manifest file is not valid JSON${NC}" + exit 1 + fi + else + # Basic JSON validation without jq + if grep -q '^\s*{' "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json" && grep -q '}\s*$' "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json"; then + echo -e "${GREEN}✓ Manifest file appears to be JSON (basic check)${NC}" + else + echo -e "${RED}✗ Manifest file does not appear to be valid JSON${NC}" + exit 1 + fi + fi + + echo -e "${GREEN}🎉 Fresh install test completed successfully!${NC}" + echo -e "${GREEN}All installation artifacts verified:${NC}" + echo -e "${GREEN} - Root directory: $TX3_ROOT_DIR${NC}" + echo -e "${GREEN} - Channel: $TX3_CHANNEL${NC}" + echo -e "${GREEN} - Channel directory: $TX3_ROOT_DIR/$TX3_CHANNEL${NC}" + echo -e "${GREEN} - Binary directory: $TX3_ROOT_DIR/$TX3_CHANNEL/bin${NC}" + echo -e "${GREEN} - Manifest file: $TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json${NC}" + echo -e "${GREEN} - Executable binaries: $bin_count${NC}" +} + +# Run the main test +main "$@" \ No newline at end of file diff --git a/tests/e2e/update_install.sh b/tests/e2e/update_install.sh new file mode 100755 index 0000000..6e83e9c --- /dev/null +++ b/tests/e2e/update_install.sh @@ -0,0 +1,220 @@ +#!/bin/bash + +# Update Install E2E Test for tx3up +# This test verifies that tx3up can update an existing installation of the toolchain. + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Test configuration +TEST_NAME="update_install" +TEMP_DIR=$(mktemp -d) +export TX3_ROOT_DIR="$TEMP_DIR/tx3_test" +export TX3_CHANNEL="${TX3_CHANNEL:-stable}" + +echo -e "${YELLOW}Starting $TEST_NAME test...${NC}" +echo "TX3_ROOT_DIR: $TX3_ROOT_DIR" +echo "TX3_CHANNEL: $TX3_CHANNEL" +echo "Temp directory: $TEMP_DIR" + +# Cleanup function +cleanup() { + echo -e "${YELLOW}Cleaning up test artifacts...${NC}" + rm -rf "$TEMP_DIR" +} +trap cleanup EXIT + +# Function to check if a file exists and is executable +check_executable() { + local file_path="$1" + local description="$2" + + if [[ -f "$file_path" && -x "$file_path" ]]; then + echo -e "${GREEN}✓ $description found and executable: $file_path${NC}" + return 0 + else + echo -e "${RED}✗ $description not found or not executable: $file_path${NC}" + return 1 + fi +} + +# Function to check if a directory exists +check_directory() { + local dir_path="$1" + local description="$2" + + if [[ -d "$dir_path" ]]; then + echo -e "${GREEN}✓ $description exists: $dir_path${NC}" + return 0 + else + echo -e "${RED}✗ $description does not exist: $dir_path${NC}" + return 1 + fi +} + +# Function to check if a file exists +check_file() { + local file_path="$1" + local description="$2" + + if [[ -f "$file_path" ]]; then + echo -e "${GREEN}✓ $description exists: $file_path${NC}" + return 0 + else + echo -e "${RED}✗ $description does not exist: $file_path${NC}" + return 1 + fi +} + +# Function to get file modification time +get_file_mtime() { + local file_path="$1" + if [[ -f "$file_path" ]]; then + stat -c %Y "$file_path" 2>/dev/null || stat -f %m "$file_path" 2>/dev/null || echo "0" + else + echo "0" + fi +} + +# Function to count files in directory +count_files() { + local dir_path="$1" + if [[ -d "$dir_path" ]]; then + find "$dir_path" -type f 2>/dev/null | wc -l + else + echo "0" + fi +} + +# Main test execution +main() { + echo -e "${YELLOW}Step 1: Performing initial installation${NC}" + + # Ensure clean state + if [[ -e "$TX3_ROOT_DIR" ]]; then + rm -rf "$TX3_ROOT_DIR" + fi + + # Run initial installation + if ! ./target/release/tx3up; then + echo -e "${RED}✗ Initial tx3up installation failed${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ Initial installation completed${NC}" + + # Verify initial installation + check_directory "$TX3_ROOT_DIR" "TX3 root directory" + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL" "Channel directory ($TX3_CHANNEL)" + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL/bin" "Binary directory" + check_file "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json" "Manifest file" + + echo -e "${YELLOW}Step 2: Recording initial state${NC}" + + # Record initial state + initial_manifest_mtime=$(get_file_mtime "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json") + initial_bin_count=$(count_files "$TX3_ROOT_DIR/$TX3_CHANNEL/bin") + + echo "Initial manifest mtime: $initial_manifest_mtime" + echo "Initial binary count: $initial_bin_count" + + # Create a test marker file to verify update behavior + test_marker="$TX3_ROOT_DIR/test_marker.txt" + echo "test_marker_$(date +%s)" > "$test_marker" + + # Wait a moment to ensure different timestamps + sleep 2 + + echo -e "${YELLOW}Step 3: Running update installation${NC}" + + # Run the installer again (should update existing installation) + if ! ./target/release/tx3up; then + echo -e "${RED}✗ tx3up update installation failed${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ Update installation completed${NC}" + + echo -e "${YELLOW}Step 4: Verifying update behavior${NC}" + + # Verify installation still exists and is functional + check_directory "$TX3_ROOT_DIR" "TX3 root directory (after update)" + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL" "Channel directory (after update)" + check_directory "$TX3_ROOT_DIR/$TX3_CHANNEL/bin" "Binary directory (after update)" + check_file "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json" "Manifest file (after update)" + + # Check if our test marker still exists (should be preserved during update) + if [[ -f "$test_marker" ]]; then + echo -e "${GREEN}✓ Test marker file preserved during update${NC}" + else + echo -e "${YELLOW}⚠ Test marker file not preserved (acceptable behavior)${NC}" + fi + + # Record post-update state + updated_manifest_mtime=$(get_file_mtime "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json") + updated_bin_count=$(count_files "$TX3_ROOT_DIR/$TX3_CHANNEL/bin") + + echo "Updated manifest mtime: $updated_manifest_mtime" + echo "Updated binary count: $updated_bin_count" + + echo -e "${YELLOW}Step 5: Analyzing update results${NC}" + + # Check if update had any effect (manifests should be same or newer) + if [[ $updated_manifest_mtime -ge $initial_manifest_mtime ]]; then + echo -e "${GREEN}✓ Manifest file timestamp is same or newer after update${NC}" + else + echo -e "${RED}✗ Manifest file timestamp is older after update${NC}" + exit 1 + fi + + # Check if binary count is maintained or increased + if [[ $updated_bin_count -ge $initial_bin_count ]]; then + echo -e "${GREEN}✓ Binary count maintained or increased: $initial_bin_count → $updated_bin_count${NC}" + else + echo -e "${RED}✗ Binary count decreased after update: $initial_bin_count → $updated_bin_count${NC}" + exit 1 + fi + + # Verify that at least some binaries are still executable + executable_count=$(find "$TX3_ROOT_DIR/$TX3_CHANNEL/bin" -type f -executable 2>/dev/null | wc -l) + if [[ $executable_count -gt 0 ]]; then + echo -e "${GREEN}✓ Found $executable_count executable binaries after update${NC}" + else + echo -e "${RED}✗ No executable binaries found after update${NC}" + exit 1 + fi + + echo -e "${YELLOW}Step 6: Testing idempotency${NC}" + + # Run installer one more time to test idempotency + if ! ./target/release/tx3up; then + echo -e "${RED}✗ tx3up idempotency test failed${NC}" + exit 1 + fi + + # Verify installation is still intact + final_manifest_mtime=$(get_file_mtime "$TX3_ROOT_DIR/$TX3_CHANNEL/manifest.json") + final_bin_count=$(count_files "$TX3_ROOT_DIR/$TX3_CHANNEL/bin") + + if [[ $final_bin_count -eq $updated_bin_count ]]; then + echo -e "${GREEN}✓ Idempotency test passed - binary count unchanged${NC}" + else + echo -e "${YELLOW}⚠ Binary count changed during idempotency test: $updated_bin_count → $final_bin_count${NC}" + fi + + echo -e "${GREEN}🎉 Update install test completed successfully!${NC}" + echo -e "${GREEN}Update test results:${NC}" + echo -e "${GREEN} - Initial binary count: $initial_bin_count${NC}" + echo -e "${GREEN} - Updated binary count: $updated_bin_count${NC}" + echo -e "${GREEN} - Final binary count: $final_bin_count${NC}" + echo -e "${GREEN} - Installation directory: $TX3_ROOT_DIR${NC}" + echo -e "${GREEN} - Manifest updates: $initial_manifest_mtime → $updated_manifest_mtime → $final_manifest_mtime${NC}" +} + +# Run the main test +main "$@" \ No newline at end of file