name: Sanity Testing on: push: branches: - main - conv_sanity workflow_dispatch: inputs: user: description: 'User to run sanity test on' permissions: # required to retrieve AWS credentials id-token: write contents: write # cancel currently running jobs if a new version of the branch is pushed concurrency: group: sanity_testing-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: SetM365App: uses: alcionai/corso/.github/workflows/accSelector.yaml@main Sanity-Tests: needs: [ SetM365App ] environment: Testing runs-on: ubuntu-latest env: # Need these in the local env so that corso can read them AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY_SECRET }} AZURE_CLIENT_ID: ${{ secrets[needs.SetM365App.outputs.client_id_env] }} AZURE_CLIENT_SECRET: ${{ secrets[needs.SetM365App.outputs.client_secret_env] }} AZURE_TENANT_ID: ${{ secrets.TENANT_ID }} CORSO_PASSPHRASE: ${{ secrets.INTEGRATION_TEST_CORSO_PASSPHRASE }} # re-used values CORSO_LOG_DIR: ${{ github.workspace }}/src/testlog CORSO_LOG_FILE: ${{ github.workspace }}/src/testlog/run-sanity.log RESTORE_DEST_PFX: Corso_Test_Sanity_ TEST_USER: ${{ github.event.inputs.user != '' && github.event.inputs.user || vars.CORSO_M365_TEST_USER_ID }} defaults: run: working-directory: src ########################################################################################################################################## # setup steps: - uses: actions/checkout@v4 - name: Setup Golang with cache uses: magnetikonline/action-golang-cache@v4 with: go-version-file: src/go.mod - run: go build -o corso timeout-minutes: 10 - run: go build -o sanity-test ./cmd/sanity_test timeout-minutes: 10 - run: mkdir ${CORSO_LOG_DIR} ########################################################################################################################################## # Pre-Run cleanup # unlike CI tests, sanity tests are not expected to run concurrently. # however, the sanity yaml concurrency is set to a maximum of 1 run, preferring # the latest release. If we wait to clean up the production til after the tests # It would be possible to complete all the testing but cancel the run before # cleanup occurs. Setting the cleanup before the tests ensures we always begin # with a clean slate, and cannot compound data production. - name: Set purge boundary if: always() run: | echo "NOW=$(date +"%Y-%m-%dT%H:%M:%SZ")" >> $GITHUB_ENV - name: Purge CI-Produced Folders for Users timeout-minutes: 30 uses: ./.github/actions/purge-m365-data with: user: ${{ env.TEST_USER }} folder-prefix: ${{ env.RESTORE_DEST_PFX }} older-than: ${{ env.NOW }} azure-client-id: ${{ secrets[needs.SetM365App.outputs.client_id_env] }} azure-client-secret: ${{ secrets[needs.SetM365App.outputs.client_secret_env] }} azure-tenant-id: ${{ secrets.TENANT_ID }} m365-admin-user: ${{ secrets.M365_TENANT_ADMIN_USER }} m365-admin-password: ${{ secrets.M365_TENANT_ADMIN_PASSWORD }} - name: Purge CI-Produced Folders for Sites timeout-minutes: 30 if: always() uses: ./.github/actions/purge-m365-data with: site: ${{ vars.CORSO_M365_TEST_SITE_URL }} folder-prefix: ${{ env.RESTORE_DEST_PFX }} libraries: ${{ vars.CORSO_M365_TEST_SITE_LIBRARIES }} older-than: ${{ env.NOW }} azure-client-id: ${{ secrets[needs.SetM365App.outputs.client_id_env] }} azure-client-secret: ${{ secrets[needs.SetM365App.outputs.client_secret_env] }} azure-tenant-id: ${{ secrets.TENANT_ID }} m365-admin-user: ${{ secrets.M365_TENANT_ADMIN_USER }} m365-admin-password: ${{ secrets.M365_TENANT_ADMIN_PASSWORD }} ########################################################################################################################################## # Repository commands - name: Version Test timeout-minutes: 10 run: | ./corso --version | grep -c 'Corso version:' - name: Repo init test timeout-minutes: 10 id: repo-init run: | set -euo pipefail prefix=$(date +"%Y-%m-%d-%T") echo -e "\nRepo init test\n" >> ${{ env.CORSO_LOG_FILE }} ./corso repo init s3 \ --no-stats \ --hide-progress \ --prefix $prefix \ --bucket ${{ secrets.CI_TESTS_S3_BUCKET }} \ 2>&1 | tee ${{ env.CORSO_LOG_DIR }}/gotest-repo-init.log if ! grep -q 'Initialized a S3 repository within bucket' ${{ env.CORSO_LOG_DIR }}/gotest-repo-init.log then echo "Repo could not be initialized" exit 1 fi echo result="$prefix" >> $GITHUB_OUTPUT - name: Repo connect test timeout-minutes: 10 run: | set -euo pipefail echo -e "\nRepo connect test\n" >> ${{ env.CORSO_LOG_FILE }} ./corso repo connect s3 \ --no-stats \ --hide-progress \ --prefix ${{ steps.repo-init.outputs.result }} \ --bucket ${{ secrets.CI_TESTS_S3_BUCKET }} \ 2>&1 | tee ${{ env.CORSO_LOG_DIR }}/gotest-repo-connect.log if ! grep -q 'Connected to S3 bucket' ${{ env.CORSO_LOG_DIR }}/gotest-repo-connect.log then echo "Repo could not be connected" exit 1 fi # Run maintenance on an empty repo just to make sure the command still # works. - name: Repo maintenance test timeout-minutes: 30 run: | set -euo pipefail echo -e "\nRepo maintenance test\n" >> ${{ env.CORSO_LOG_FILE }} ./corso repo maintenance \ --no-stats \ --hide-progress \ --mode complete \ 2>&1 | tee ${{ env.CORSO_LOG_DIR }}/gotest-repo-maintenance.log ########################################################################################################################################## # # Exchange # # generate new entries to roll into the next load test # # only runs if the test was successful # - name: Exchange - Create new data # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # go run . exchange emails \ # --user ${{ env.TEST_USER }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }} \ # --count 4 # - name: Exchange - Backup # timeout-minutes: 30 # id: exchange-backup # uses: ./.github/actions/backup-restore-test # with: # service: exchange # kind: first-backup # backup-args: '--mailbox "${{ env.TEST_USER }}" --data "email"' # restore-args: '--email-folder ${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # - name: Exchange - Incremental backup # timeout-minutes: 30 # id: exchange-backup-incremental # uses: ./.github/actions/backup-restore-test # with: # service: exchange # kind: incremental # backup-args: '--mailbox "${{ env.TEST_USER }}" --data "email"' # restore-args: '--email-folder ${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # backup-id: ${{ steps.exchange-backup.outputs.backup-id }} # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # - name: Exchange - Non delta backup # timeout-minutes: 30 # id: exchange-backup-non-delta # uses: ./.github/actions/backup-restore-test # with: # service: exchange # kind: non-delta # backup-args: '--mailbox "${{ env.TEST_USER }}" --data "email" --disable-delta' # restore-args: '--email-folder ${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # backup-id: ${{ steps.exchange-backup.outputs.backup-id }} # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # - name: Exchange - Incremental backup after non-delta # timeout-minutes: 30 # id: exchange-backup-incremental-after-non-delta # uses: ./.github/actions/backup-restore-test # with: # service: exchange # kind: non-delta-incremental # backup-args: '--mailbox "${{ env.TEST_USER }}" --data "email"' # restore-args: '--email-folder ${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.repo-init.outputs.result }}' # backup-id: ${{ steps.exchange-backup.outputs.backup-id }} # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true ########################################################################################################################################## # # Onedrive # # generate new entries for test # - name: OneDrive - Create new data # id: new-data-creation-onedrive # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # suffix=$(date +"%Y-%m-%d_%H-%M-%S") # go run . onedrive files \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}$suffix \ # --count 4 # echo result="${suffix}" >> $GITHUB_OUTPUT # - name: OneDrive - Backup # id: onedrive-backup # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: onedrive # kind: first-backup # backup-args: '--user "${{ env.TEST_USER }}"' # restore-args: '--folder ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-onedrive.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-onedrive.outputs.result }}' # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # # generate some more enteries for incremental check # - name: OneDrive - Create new data (for incremental) # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # go run . onedrive files \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-onedrive.outputs.result }} \ # --count 4 # - name: OneDrive - Incremental backup # id: onedrive-incremental # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: onedrive # kind: incremental # backup-args: '--user "${{ env.TEST_USER }}"' # restore-args: '--folder ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-onedrive.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-onedrive.outputs.result }}' # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # ########################################################################################################################################## # # Sharepoint Library # # generate new entries for test # - name: SharePoint - Create new data # id: new-data-creation-sharepoint # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # suffix=$(date +"%Y-%m-%d_%H-%M-%S") # go run . sharepoint files \ # --site ${{ vars.CORSO_M365_TEST_SITE_URL }} \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}$suffix \ # --count 4 # echo result="${suffix}" >> $GITHUB_OUTPUT # - name: SharePoint - Backup # id: sharepoint-backup # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: sharepoint # kind: first-backup # backup-args: '--site "${{ vars.CORSO_M365_TEST_SITE_URL }}" --data libraries' # restore-args: '--folder ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-sharepoint.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-sharepoint.outputs.result }}' # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # category: libraries # # generate some more enteries for incremental check # - name: SharePoint - Create new data (for incremental) # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # go run . sharepoint files \ # --site ${{ vars.CORSO_M365_TEST_SITE_URL }} \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-sharepoint.outputs.result }} \ # --count 4 # - name: SharePoint - Incremental backup # id: sharepoint-incremental # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: sharepoint # kind: incremental # backup-args: '--site "${{ vars.CORSO_M365_TEST_SITE_URL }}" --data libraries' # restore-args: '--folder ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-sharepoint.outputs.result }}' # restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-sharepoint.outputs.result }}' # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # category: libraries # ########################################################################################################################################## # # Sharepoint Lists # # generate new entries for test # # The `awk | tr | sed` command chain is used to get a comma separated list of SharePoint list names. # - name: SharePoint Lists - Create new data # id: new-data-creation-sharepoint-lists # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # suffix=$(date +"%Y-%m-%d_%H-%M-%S") # go run . sharepoint lists \ # --site ${{ vars.CORSO_M365_TEST_SITE_URL }} \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}$suffix \ # --count 4 | # awk 'NR > 1 {print $2}' | tr '\n' ',' | sed -e 's/,$//' -e 's/^/result=/' | # tee $GITHUB_OUTPUT # # Extracts the common prefix for the Sharepoint list names. # - name: SharePoint Lists - Store restore container # id: sharepoint-lists-store-restore-container # run: | # echo ${{ steps.new-data-creation-sharepoint-lists.outputs.result }} | # cut -d',' -f1 | # cut -d'_' -f1,2,3,4,5 | # sed -e 's/^/result=/' | # tee $GITHUB_OUTPUT # - name: SharePoint Lists - Backup # id: sharepoint-lists-backup # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: sharepoint # kind: first-backup-lists # backup-args: '--site "${{ vars.CORSO_M365_TEST_SITE_URL }}" --data lists' # restore-args: "--list ${{ steps.new-data-creation-sharepoint-lists.outputs.result }} --destination Corso_Test_Sanity_Restore_$(date +'%Y%m%d_%H%M%S') --allow-lists-restore" # export-args: "--list ${{ steps.new-data-creation-sharepoint-lists.outputs.result }}" # restore-container: "${{ steps.sharepoint-lists-store-restore-container.outputs.result }}" # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # category: lists # on-collision: copy # # generate some more enteries for incremental check # - name: SharePoint Lists - Create new data (for incremental) # id: inc-data-creation-sharepoint-lists # timeout-minutes: 30 # working-directory: ./src/cmd/factory # run: | # suffix=$(date +"%Y-%m-%d_%H-%M-%S") # go run . sharepoint lists \ # --site ${{ vars.CORSO_M365_TEST_SITE_URL }} \ # --user ${{ env.TEST_USER }} \ # --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ # --tenant ${{ secrets.TENANT_ID }} \ # --destination ${{ env.RESTORE_DEST_PFX }}$suffix \ # --count 4 | # awk 'NR > 1 {print $2}' | tr '\n' ',' | sed -e 's/,$//' -e 's/^/result=/' | # tee $GITHUB_OUTPUT # - name: SharePoint Lists - Store restore container (for incremental) # id: sharepoint-lists-store-restore-container-inc # run: | # echo ${{ steps.inc-data-creation-sharepoint-lists.outputs.result }} | # cut -d',' -f1 | # cut -d'_' -f1,2,3,4,5 | # sed -e 's/^/result=/' | # tee $GITHUB_OUTPUT # - name: SharePoint Lists - Incremental backup # id: sharepoint-lists-incremental # timeout-minutes: 30 # uses: ./.github/actions/backup-restore-test # with: # service: sharepoint # kind: incremental-lists # backup-args: '--site "${{ vars.CORSO_M365_TEST_SITE_URL }}" --data lists' # restore-args: "--list ${{ steps.inc-data-creation-sharepoint-lists.outputs.result }},${{ steps.new-data-creation-sharepoint-lists.outputs.result }} --destination Corso_Test_Sanity_Restore_$(date +'%Y%m%d_%H%M%S') --allow-lists-restore" # export-args: "--list ${{ steps.inc-data-creation-sharepoint-lists.outputs.result }},${{ steps.new-data-creation-sharepoint-lists.outputs.result }}" # restore-container: "${{ steps.sharepoint-lists-store-restore-container-inc.outputs.result }},${{ steps.sharepoint-lists-store-restore-container.outputs.result }}" # log-dir: ${{ env.CORSO_LOG_DIR }} # with-export: true # category: lists # on-collision: copy ########################################################################################################################################## # Groups and Teams # generate new entries for test - name: Groups - Create new data id: new-data-creation-groups timeout-minutes: 30 working-directory: ./src/cmd/factory run: | suffix=$(date +"%Y-%m-%d_%H-%M-%S") go run . sharepoint files \ --site ${{ vars.CORSO_M365_TEST_GROUPS_SITE_URL }} \ --user ${{ env.TEST_USER }} \ --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ --tenant ${{ secrets.TENANT_ID }} \ --destination ${{ env.RESTORE_DEST_PFX }}$suffix \ --count 4 echo result="${suffix}" >> $GITHUB_OUTPUT - name: Groups - Backup id: groups-backup timeout-minutes: 30 uses: ./.github/actions/backup-restore-test with: service: groups kind: first-backup backup-args: '--group "${{ vars.CORSO_M365_TEST_TEAM_ID }}"' restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-groups.outputs.result }}' log-dir: ${{ env.CORSO_LOG_DIR }} with-export: true # generate some more entries for incremental check - name: Groups - Create new data (for incremental) timeout-minutes: 30 working-directory: ./src/cmd/factory run: | go run . sharepoint files \ --site ${{ vars.CORSO_M365_TEST_GROUPS_SITE_URL }} \ --user ${{ env.TEST_USER }} \ --secondaryuser ${{ env.CORSO_SECONDARY_M365_TEST_USER_ID }} \ --tenant ${{ secrets.TENANT_ID }} \ --destination ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-groups.outputs.result }} \ --count 4 - name: Groups - Incremental backup id: groups-incremental timeout-minutes: 30 uses: ./.github/actions/backup-restore-test with: service: groups kind: incremental backup-args: '--group "${{ vars.CORSO_M365_TEST_TEAM_ID }}"' restore-args: '--site "${{ vars.CORSO_M365_TEST_GROUPS_SITE_URL }}" --folder ${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-groups.outputs.result }}' restore-container: '${{ env.RESTORE_DEST_PFX }}${{ steps.new-data-creation-groups.outputs.result }}' log-dir: ${{ env.CORSO_LOG_DIR }} with-export: true ########################################################################################################################################## # Logging & Notifications # Upload the original go test output as an artifact for later review. - name: Upload test log if: always() uses: actions/upload-artifact@v4 with: name: sanity-test-log path: ${{ env.CORSO_LOG_DIR }}/* if-no-files-found: error retention-days: 14 - name: Notify failure in teams if: failure() uses: ./.github/actions/teams-message with: msg: "[FAILED] Sanity Tests" #teams_url: ${{ secrets.TEAMS_CORSO_CI_WEBHOOK_URL }}