├── .editorconfig ├── .github └── workflows │ ├── linting.yml │ ├── linux.yml │ ├── macos-10.yml │ ├── macos-11.yml │ └── ssh.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── tests ├── .lib │ ├── create-source.sh │ ├── dir-size.sh │ ├── file-exist.sh │ ├── file-owner.sh │ ├── file-permissions.sh │ ├── file-size.sh │ ├── file-time.sh │ ├── functions.sh │ ├── print.sh │ └── run-backup.sh ├── 01-run-local-default-abs-noslash-noslash.sh ├── 01-run-local-default-abs-noslash-slash.sh ├── 01-run-local-default-abs-slash-noslash.sh ├── 01-run-local-default-abs-slash-slash.sh ├── 02-run-local-default-rel-noslash-noslash.sh ├── 02-run-local-default-rel-noslash-slash.sh ├── 02-run-local-default-rel-slash-noslash.sh ├── 02-run-local-default-rel-slash-slash.sh ├── 03-run-local-no_perms.sh ├── 04-run-local-no_times.sh ├── 05-run-local-copy_links.sh ├── 06-run-local-crazy-filename-chars.sh ├── 06-run-local-crazy-pathname-chars.sh ├── 10-run-remote-default-abs.sh ├── 10-run-remote-default-rel.sh ├── 11-run-remote-ssh_port_1111-nouser.sh ├── 11-run-remote-ssh_port_1111-user.sh ├── 11-run-remote-ssh_port_22-nouser.sh ├── 11-run-remote-ssh_port_22-user.sh ├── 11-run-remote-ssh_port_def-nouser.sh ├── 11-run-remote-ssh_port_def-user.sh ├── 12-run-remote-ssh_config-default.sh ├── 12-run-remote-ssh_config-port_1111.sh ├── 12-run-remote-ssh_config-port_overwrite.sh ├── 13-run-remote-crazy-source-pathname-chars.sh ├── docker-compose.yml ├── docker-ssh-client │ ├── Dockerfile │ ├── README.md │ ├── docker-entrypoint.sh │ └── id_rsa └── docker-ssh-server │ ├── Dockerfile │ ├── README.md │ └── id_rsa.pub └── timemachine /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Default configuration 5 | # ------------------------------------------------------------------------------------------------- 6 | # top-most EditorConfig file 7 | root = true 8 | 9 | # Default for all files 10 | [*] 11 | charset = utf-8 12 | end_of_line = lf 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | 16 | [*.{yml,yaml}] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.sh] 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | [Makefile] 25 | indent_style = tab 26 | indent_size = 4 27 | 28 | [*.md] 29 | indent_style = space 30 | trim_trailing_whitespace = false 31 | indent_size = 2 32 | -------------------------------------------------------------------------------- /.github/workflows/linting.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: Linting 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs on Pull Requests 14 | pull_request: 15 | 16 | # Runs on master Branch and Tags 17 | push: 18 | branches: 19 | - master 20 | tags: 21 | - '[0-9]+.[0-9]+*' 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # What to run 26 | # ------------------------------------------------------------------------------------------------- 27 | jobs: 28 | linting: 29 | 30 | runs-on: ubuntu-latest 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | target: 36 | - lint-file 37 | - lint-shell 38 | 39 | name: "[${{ matrix.target}}]" 40 | steps: 41 | 42 | # ------------------------------------------------------------ 43 | # Checkout repository 44 | # ------------------------------------------------------------ 45 | - name: Checkout repository 46 | uses: actions/checkout@v1 47 | 48 | - name: Show environment 49 | shell: bash 50 | run: | 51 | env 52 | 53 | - name: Show bash versions 54 | shell: bash 55 | run: | 56 | bash --version 57 | 58 | # ------------------------------------------------------------ 59 | # Lint 60 | # ------------------------------------------------------------ 61 | - name: Pull Artifacts 62 | shell: bash 63 | run: | 64 | while ! make pull-docker-${TARGET}; do sleep 1; done 65 | env: 66 | TARGET: ${{ matrix.target }} 67 | 68 | - name: Lint 69 | shell: bash 70 | run: | 71 | make ${TARGET} 72 | env: 73 | TARGET: ${{ matrix.target }} 74 | -------------------------------------------------------------------------------- /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: Linux 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs on Pull Requests 14 | pull_request: 15 | 16 | # Runs on master Branch and Tags 17 | push: 18 | branches: 19 | - master 20 | tags: 21 | - '[0-9]+.[0-9]+*' 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # What to run 26 | # ------------------------------------------------------------------------------------------------- 27 | jobs: 28 | linux: 29 | 30 | runs-on: ubuntu-latest 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | target: 36 | - test-local-default-abs-noslash-noslash 37 | - test-local-default-abs-noslash-slash 38 | - test-local-default-abs-slash-noslash 39 | - test-local-default-abs-slash-slash 40 | - test-local-default-rel-noslash-noslash 41 | - test-local-default-rel-noslash-slash 42 | - test-local-default-rel-slash-noslash 43 | - test-local-default-rel-slash-slash 44 | - test-local-no_perms 45 | - test-local-no_times 46 | - test-local-copy_links 47 | - test-local-crazy-filename-chars 48 | - test-local-crazy-pathname-chars 49 | 50 | name: "[Linux ${{ matrix.target }}]" 51 | steps: 52 | 53 | # ------------------------------------------------------------ 54 | # Checkout repository 55 | # ------------------------------------------------------------ 56 | - name: Checkout repository 57 | uses: actions/checkout@v1 58 | 59 | - name: Show environment 60 | shell: bash 61 | run: | 62 | env 63 | 64 | - name: Show user 65 | shell: bash 66 | run: | 67 | id 68 | 69 | - name: Show bash versions 70 | shell: bash 71 | run: | 72 | bash --version 73 | 74 | - name: Show rsync versions 75 | shell: bash 76 | run: | 77 | rsync --version 78 | 79 | # ------------------------------------------------------------ 80 | # Install 81 | # ------------------------------------------------------------ 82 | - name: Install 83 | shell: bash 84 | run: | 85 | sudo make install 86 | /usr/local/bin/timemachine --version 87 | 88 | # ------------------------------------------------------------ 89 | # Test 90 | # ------------------------------------------------------------ 91 | - name: Test 92 | shell: bash 93 | run: | 94 | make ${TARGET} 95 | env: 96 | TARGET: ${{ matrix.target }} 97 | 98 | # ------------------------------------------------------------ 99 | # Uninstall 100 | # ------------------------------------------------------------ 101 | - name: Uninstall 102 | shell: bash 103 | run: | 104 | sudo make uninstall 105 | if test -f /usr/local/bin/timemachine >/dev/null 2>&1; then false; fi 106 | -------------------------------------------------------------------------------- /.github/workflows/macos-10.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: MacOS-10 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs on Pull Requests 14 | pull_request: 15 | 16 | # Runs on master Branch and Tags 17 | push: 18 | branches: 19 | - master 20 | tags: 21 | - '[0-9]+.[0-9]+*' 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # What to run 26 | # ------------------------------------------------------------------------------------------------- 27 | jobs: 28 | macos-10: 29 | 30 | runs-on: macos-10.15 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | target: 36 | - test-local-default-abs-noslash-noslash 37 | - test-local-default-abs-noslash-slash 38 | - test-local-default-abs-slash-noslash 39 | - test-local-default-abs-slash-slash 40 | - test-local-default-rel-noslash-noslash 41 | - test-local-default-rel-noslash-slash 42 | - test-local-default-rel-slash-noslash 43 | - test-local-default-rel-slash-slash 44 | - test-local-no_perms 45 | - test-local-no_times 46 | - test-local-copy_links 47 | - test-local-crazy-filename-chars 48 | - test-local-crazy-pathname-chars 49 | 50 | name: "[MacOS ${{ matrix.target }}]" 51 | steps: 52 | 53 | # ------------------------------------------------------------ 54 | # Checkout repository 55 | # ------------------------------------------------------------ 56 | - name: Checkout repository 57 | uses: actions/checkout@v1 58 | 59 | - name: Show environment 60 | shell: bash 61 | run: | 62 | env 63 | 64 | - name: Show user 65 | shell: bash 66 | run: | 67 | id 68 | 69 | - name: Show bash versions 70 | shell: bash 71 | run: | 72 | bash --version 73 | 74 | - name: Show rsync versions 75 | shell: bash 76 | run: | 77 | rsync --version 78 | 79 | # ------------------------------------------------------------ 80 | # Install 81 | # ------------------------------------------------------------ 82 | - name: Install 83 | shell: bash 84 | run: | 85 | sudo make install 86 | /usr/local/bin/timemachine --version 87 | 88 | # ------------------------------------------------------------ 89 | # Test 90 | # ------------------------------------------------------------ 91 | - name: Test 92 | shell: bash 93 | run: | 94 | make ${TARGET} 95 | env: 96 | TARGET: ${{ matrix.target }} 97 | 98 | # ------------------------------------------------------------ 99 | # Uninstall 100 | # ------------------------------------------------------------ 101 | - name: Uninstall 102 | shell: bash 103 | run: | 104 | sudo make uninstall 105 | if test -f /usr/local/bin/timemachine >/dev/null 2>&1; then false; fi 106 | -------------------------------------------------------------------------------- /.github/workflows/macos-11.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: MacOS-11 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs on Pull Requests 14 | pull_request: 15 | 16 | # Runs on master Branch and Tags 17 | push: 18 | branches: 19 | - master 20 | tags: 21 | - '[0-9]+.[0-9]+*' 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # What to run 26 | # ------------------------------------------------------------------------------------------------- 27 | jobs: 28 | macos-11: 29 | 30 | runs-on: macos-11 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | target: 36 | - test-local-default-abs-noslash-noslash 37 | - test-local-default-abs-noslash-slash 38 | - test-local-default-abs-slash-noslash 39 | - test-local-default-abs-slash-slash 40 | - test-local-default-rel-noslash-noslash 41 | - test-local-default-rel-noslash-slash 42 | - test-local-default-rel-slash-noslash 43 | - test-local-default-rel-slash-slash 44 | - test-local-no_perms 45 | - test-local-no_times 46 | - test-local-copy_links 47 | - test-local-crazy-filename-chars 48 | - test-local-crazy-pathname-chars 49 | 50 | name: "[MacOS ${{ matrix.target }}]" 51 | steps: 52 | 53 | # ------------------------------------------------------------ 54 | # Checkout repository 55 | # ------------------------------------------------------------ 56 | - name: Checkout repository 57 | uses: actions/checkout@v1 58 | 59 | - name: Show environment 60 | shell: bash 61 | run: | 62 | env 63 | 64 | - name: Show user 65 | shell: bash 66 | run: | 67 | id 68 | 69 | - name: Show bash versions 70 | shell: bash 71 | run: | 72 | bash --version 73 | 74 | - name: Show rsync versions 75 | shell: bash 76 | run: | 77 | rsync --version 78 | 79 | # ------------------------------------------------------------ 80 | # Install 81 | # ------------------------------------------------------------ 82 | - name: Install 83 | shell: bash 84 | run: | 85 | sudo make install 86 | /usr/local/bin/timemachine --version 87 | 88 | # ------------------------------------------------------------ 89 | # Test 90 | # ------------------------------------------------------------ 91 | - name: Test 92 | shell: bash 93 | run: | 94 | make ${TARGET} 95 | env: 96 | TARGET: ${{ matrix.target }} 97 | 98 | # ------------------------------------------------------------ 99 | # Uninstall 100 | # ------------------------------------------------------------ 101 | - name: Uninstall 102 | shell: bash 103 | run: | 104 | sudo make uninstall 105 | if test -f /usr/local/bin/timemachine >/dev/null 2>&1; then false; fi 106 | -------------------------------------------------------------------------------- /.github/workflows/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # ------------------------------------------------------------------------------------------------- 4 | # Job Name 5 | # ------------------------------------------------------------------------------------------------- 6 | name: SSH 7 | 8 | 9 | # ------------------------------------------------------------------------------------------------- 10 | # When to run 11 | # ------------------------------------------------------------------------------------------------- 12 | on: 13 | # Runs on Pull Requests 14 | pull_request: 15 | 16 | # Runs on master Branch and Tags 17 | push: 18 | branches: 19 | - master 20 | tags: 21 | - '[0-9]+.[0-9]+*' 22 | 23 | 24 | # ------------------------------------------------------------------------------------------------- 25 | # What to run 26 | # ------------------------------------------------------------------------------------------------- 27 | jobs: 28 | ssh: 29 | 30 | runs-on: ubuntu-latest 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | target: 36 | - test-remote-default-abs 37 | - test-remote-default-rel 38 | - test-remote-ssh_1111_port-nouser 39 | - test-remote-ssh_1111_port-user 40 | - test-remote-ssh_22_port-nouser 41 | - test-remote-ssh_22_port-user 42 | - test-remote-ssh_def_port-nouser 43 | - test-remote-ssh_def_port-user 44 | - test-remote-ssh_config-default 45 | - test-remote-ssh_config-port_1111 46 | - test-remote-ssh_config-port_overwrite 47 | - test-remote-ssh_crazy-source-pathname-chars 48 | 49 | name: "[SSH ${{ matrix.target }}]" 50 | steps: 51 | 52 | # ------------------------------------------------------------ 53 | # Checkout repository 54 | # ------------------------------------------------------------ 55 | - name: Checkout repository 56 | uses: actions/checkout@v1 57 | 58 | - name: Show environment 59 | shell: bash 60 | run: | 61 | env 62 | 63 | - name: Show user 64 | shell: bash 65 | run: | 66 | id 67 | 68 | - name: Show bash versions 69 | shell: bash 70 | run: | 71 | bash --version 72 | 73 | - name: Show docker versions 74 | shell: bash 75 | run: | 76 | docker --version 77 | 78 | # ------------------------------------------------------------ 79 | # Build 80 | # ------------------------------------------------------------ 81 | - name: Build 82 | shell: bash 83 | run: | 84 | while ! make pull-docker-ssh-base; do sleep 1; done 85 | while ! make build-docker-ssh-server; do sleep 1; done 86 | while ! make build-docker-ssh-client; do sleep 1; done 87 | 88 | # ------------------------------------------------------------ 89 | # Test 90 | # ------------------------------------------------------------ 91 | - name: Test 92 | shell: bash 93 | run: | 94 | make ${TARGET} 95 | env: 96 | TARGET: ${{ matrix.target }} 97 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .tmp/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## Release v1.3.2 5 | 6 | #### Fixed 7 | - Fixed #77 Missing variable when local directory is missing 8 | 9 | 10 | ## Release v1.3.1 11 | 12 | #### Changed 13 | - Switch to semver for versioning 14 | - Wrap rsync into eval to escape paths 15 | 16 | #### Added 17 | - CI: check for special chars in file names 18 | 19 | #### Fixed 20 | - Fixed #69 special chars in source directory 21 | - Fixed #67 argument parsing 22 | 23 | 24 | ## Release v1.2 25 | 26 | #### Fixed 27 | - Fixed `identityity` typo to `identity` in option parsing loop. 28 | 29 | 30 | ## Release v1.1 31 | 32 | #### Added 33 | - [#60](https://github.com/cytopia/linux-timemachine/issues/60) Allow remote source 34 | - Allow to specify SSH key (`-i` or `--identity`) for remote connections 35 | 36 | 37 | ## Release v1.0 38 | 39 | #### Fixed 40 | - Use correct SSH port when using SSH aliases from ~/.ssh/config 41 | 42 | #### Added 43 | - Integration and regression tests for Linux, MacOS and remote backups over SSH 44 | - GitHub Actions integration 45 | 46 | #### Removed 47 | - Travis CI 48 | 49 | 50 | ## Release v0.9 51 | 52 | #### Added 53 | - [#9](https://github.com/cytopia/linux-timemachine/issues/9) Be able to backup to remote SSH host 54 | - Add debug option 55 | - Editorconfig 56 | 57 | 58 | ## Release v0.8 59 | 60 | #### Changed 61 | - [#22](https://github.com/cytopia/linux-timemachine/issues/22) Use `--owner`, `--group` and `--perms` by default 62 | 63 | 64 | ## Release v0.7 65 | 66 | #### Changed 67 | - [#21](https://github.com/cytopia/linux-timemachine/issues/21) No preservation of symlinks 68 | 69 | 70 | ## Release v0.6 71 | 72 | #### Fixed 73 | - [#30](https://github.com/cytopia/linux-timemachine/issues/30) Actually NOT incremental ? 74 | - [#28](https://github.com/cytopia/linux-timemachine/issues/28) Incremental issue 75 | - [#27](https://github.com/cytopia/linux-timemachine/issues/27) no hard links to old backups under busybox 76 | 77 | 78 | ## Release v0.5 79 | 80 | #### Fixed 81 | - Make incremental backups work 82 | 83 | 84 | ## Release v0.4 85 | 86 | #### Added 87 | - CHANGELOG 88 | - Add GitHub Actions for Linux 89 | - Add GitHub Actions for MacOS 90 | - install/uninstall targets 91 | 92 | #### Removed 93 | - Travis CI checks (in favour of GitHub Actions) 94 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributors are always welcome. To give you an idea what can be done: 4 | 5 | 1. Review the code 6 | 2. Simplify the code 7 | 3. Harden the code 8 | 4. Report issues 9 | 5. Extend CI tests for Linux and MacOS to ensure stability 10 | 6. Enhance FAQ section with examples 11 | 7. Improve documentation in general 12 | 8. Report lack of clarity in documentation 13 | 9. Test, test and test 14 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 cytopia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifneq (,) 2 | .error This Makefile requires GNU Make. 3 | endif 4 | 5 | 6 | # ------------------------------------------------------------------------------------------------- 7 | # Default configuration 8 | # ------------------------------------------------------------------------------------------------- 9 | 10 | .PHONY: help lint lint-file lint-shell test clean _populate 11 | 12 | SHELL := /bin/bash 13 | 14 | TEMP = temp 15 | SRC := $(TEMP)/source 16 | DST := $(TEMP)/dest 17 | 18 | FL_VERSION = 0.3 19 | FL_IGNORES = .git/,.github/ 20 | 21 | # ------------------------------------------------------------------------------------------------- 22 | # Default targets 23 | # ------------------------------------------------------------------------------------------------- 24 | 25 | help: 26 | @echo 27 | @echo "# -------------------------------------------------------------------- #" 28 | @echo "# Linux timemachine Makefile #" 29 | @echo "# -------------------------------------------------------------------- #" 30 | @echo 31 | @echo "install Install to /usr/local/bin/timemachine (requires root)" 32 | @echo "uninstall Remove /usr/local/bin/timemachine (requires root)" 33 | @echo 34 | @echo "help Show this help" 35 | @echo "lint Run shellcheck linting" 36 | @echo "test Run integration test" 37 | @echo 38 | 39 | 40 | # ------------------------------------------------------------------------------------------------- 41 | # System targets 42 | # ------------------------------------------------------------------------------------------------- 43 | 44 | install: timemachine 45 | install -d /usr/local/bin 46 | install -m 755 timemachine /usr/local/bin/timemachine 47 | 48 | 49 | uninstall: 50 | rm /usr/local/bin/timemachine 51 | 52 | 53 | # ------------------------------------------------------------------------------------------------- 54 | # Lint targets 55 | # ------------------------------------------------------------------------------------------------- 56 | 57 | lint: lint-file lint-shell 58 | 59 | 60 | lint-file: 61 | @echo "# -------------------------------------------------------------------- #" 62 | @echo "# Lint files #" 63 | @echo "# -------------------------------------------------------------------- #" 64 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-cr --text --ignore '$(FL_IGNORES)' --path . 65 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-crlf --text --ignore '$(FL_IGNORES)' --path . 66 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-trailing-single-newline --text --ignore '$(FL_IGNORES)' --path . 67 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-trailing-space --text --ignore '$(FL_IGNORES)' --path . 68 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8 --text --ignore '$(FL_IGNORES)' --path . 69 | @docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/file-lint:$(FL_VERSION) file-utf8-bom --text --ignore '$(FL_IGNORES)' --path . 70 | 71 | 72 | # ------------------------------------------------------------------------------------------------- 73 | # Test targets 74 | # ------------------------------------------------------------------------------------------------- 75 | 76 | lint-shell: 77 | @echo "# -------------------------------------------------------------------- #" 78 | @echo "# Lint shellcheck #" 79 | @echo "# -------------------------------------------------------------------- #" 80 | @docker run --rm -v $(PWD):/mnt koalaman/shellcheck:stable --shell=sh timemachine 81 | 82 | 83 | test: test-local-default-abs-noslash-noslash 84 | test: test-local-default-abs-noslash-slash 85 | test: test-local-default-abs-slash-noslash 86 | test: test-local-default-abs-slash-slash 87 | test: test-local-default-rel-noslash-noslash 88 | test: test-local-default-rel-noslash-slash 89 | test: test-local-default-rel-slash-noslash 90 | test: test-local-default-rel-slash-slash 91 | test: test-local-no_perms 92 | test: test-local-no_times 93 | test: test-local-copy_links 94 | test: test-local-crazy-filename-chars 95 | test: test-local-crazy-pathname-chars 96 | test: test-remote-default-abs 97 | test: test-remote-default-rel 98 | test: test-remote-ssh_1111_port-nouser 99 | test: test-remote-ssh_1111_port-user 100 | test: test-remote-ssh_22_port-nouser 101 | test: test-remote-ssh_22_port-user 102 | test: test-remote-ssh_def_port-nouser 103 | test: test-remote-ssh_def_port-user 104 | test: test-remote-ssh_config-default 105 | test: test-remote-ssh_config-port_1111 106 | test: test-remote-ssh_config-port_overwrite 107 | test: test-remote-ssh_crazy-source-pathname-chars 108 | 109 | test-local-default-abs-noslash-noslash: 110 | ./tests/01-run-local-default-abs-noslash-noslash.sh 111 | 112 | test-local-default-abs-noslash-slash: 113 | ./tests/01-run-local-default-abs-noslash-slash.sh 114 | 115 | test-local-default-abs-slash-noslash: 116 | ./tests/01-run-local-default-abs-slash-noslash.sh 117 | 118 | test-local-default-abs-slash-slash: 119 | ./tests/01-run-local-default-abs-slash-slash.sh 120 | 121 | test-local-default-rel-noslash-noslash: 122 | ./tests/02-run-local-default-rel-noslash-noslash.sh 123 | 124 | test-local-default-rel-noslash-slash: 125 | ./tests/02-run-local-default-rel-noslash-slash.sh 126 | 127 | test-local-default-rel-slash-noslash: 128 | ./tests/02-run-local-default-rel-slash-noslash.sh 129 | 130 | test-local-default-rel-slash-slash: 131 | ./tests/02-run-local-default-rel-slash-slash.sh 132 | 133 | test-local-no_perms: 134 | ./tests/03-run-local-no_perms.sh 135 | 136 | test-local-no_times: 137 | ./tests/04-run-local-no_times.sh 138 | 139 | test-local-copy_links: 140 | ./tests/05-run-local-copy_links.sh 141 | 142 | test-local-crazy-filename-chars: 143 | ./tests/06-run-local-crazy-filename-chars.sh 144 | 145 | test-local-crazy-pathname-chars: 146 | ./tests/06-run-local-crazy-pathname-chars.sh 147 | 148 | test-remote-default-abs: 149 | ./tests/10-run-remote-default-abs.sh 150 | 151 | test-remote-default-rel: 152 | ./tests/10-run-remote-default-rel.sh 153 | 154 | test-remote-ssh_1111_port-nouser: 155 | ./tests/11-run-remote-ssh_port_1111-nouser.sh 156 | 157 | test-remote-ssh_1111_port-user: 158 | ./tests/11-run-remote-ssh_port_1111-user.sh 159 | 160 | test-remote-ssh_22_port-nouser: 161 | ./tests/11-run-remote-ssh_port_22-nouser.sh 162 | 163 | test-remote-ssh_22_port-user: 164 | ./tests/11-run-remote-ssh_port_22-user.sh 165 | 166 | test-remote-ssh_def_port-nouser: 167 | ./tests/11-run-remote-ssh_port_def-nouser.sh 168 | 169 | test-remote-ssh_def_port-user: 170 | ./tests/11-run-remote-ssh_port_def-user.sh 171 | 172 | test-remote-ssh_config-default: 173 | ./tests/12-run-remote-ssh_config-default.sh 174 | 175 | test-remote-ssh_config-port_1111: 176 | ./tests/12-run-remote-ssh_config-port_1111.sh 177 | 178 | test-remote-ssh_config-port_overwrite: 179 | ./tests/12-run-remote-ssh_config-port_overwrite.sh 180 | 181 | test-remote-ssh_crazy-source-pathname-chars: 182 | ./tests/13-run-remote-crazy-source-pathname-chars.sh 183 | 184 | 185 | # ------------------------------------------------------------------------------------------------- 186 | # Helper targets 187 | # ------------------------------------------------------------------------------------------------- 188 | 189 | clean: 190 | @rm -rf $(TEMP) 191 | 192 | _populate: clean 193 | @mkdir -p "$(DST)" 194 | @mkdir -p "$(SRC)" 195 | @echo "a" > "$(SRC)/a" 196 | @echo "b" > "$(SRC)/b" 197 | @echo "c" > "$(SRC)/c" 198 | @chmod -w "$(SRC)/a" 199 | @chmod +x "$(SRC)/b" 200 | 201 | pull-docker-lint-file: 202 | docker pull cytopia/file-lint:$(FL_VERSION) 203 | 204 | pull-docker-lint-shell: 205 | docker pull koalaman/shellcheck:stable 206 | 207 | pull-docker-ssh-base: 208 | docker pull debian:buster-slim 209 | 210 | build-docker-ssh-server: 211 | docker build -t cytopia/ssh-server -f "$(PWD)/tests/docker-ssh-server/Dockerfile" "$(PWD)/tests/docker-ssh-server" 212 | 213 | build-docker-ssh-client: 214 | docker build -t cytopia/ssh-client -f "$(PWD)/tests/docker-ssh-client/Dockerfile" "$(PWD)/tests/docker-ssh-client" 215 | -------------------------------------------------------------------------------- /tests/.lib/create-source.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Create file 14 | ### 15 | create_file() { 16 | local src_dir="${1}" 17 | local file_name="${2}" 18 | local sub_dir= 19 | local file_path= 20 | local file_size="${3}" 21 | local file_perms="${4}" 22 | 23 | file_name="$( printf "%q" "${file_name}" )" 24 | sub_dir="$( printf "%q" "$( eval "dirname ${file_name}" )" )" 25 | file_path="${src_dir}/${file_name}" 26 | 27 | if ! eval "test -d ${src_dir}"; then 28 | printf "No such directpry: %s\\n" "${src_dir}" 29 | return 1 30 | fi 31 | # Create sub-directory if it doesn't exist 32 | if [ "${sub_dir}" != "." ]; then 33 | printf "# Create basedir: %s\\n" "${sub_dir}" 34 | run "mkdir -p ${src_dir}/${sub_dir}" 35 | fi 36 | if [ "$(uname)" = "Linux" ]; then 37 | run "dd if=/dev/zero of=${file_path} bs=1M count=${file_size} 2>/dev/null" 38 | else 39 | run "dd if=/dev/zero of=${file_path} bs=1m count=${file_size} 2>/dev/null" 40 | fi 41 | run "chmod ${file_perms} ${file_path}" 42 | 43 | if ! eval "test -f ${file_path}"; then 44 | echo "No file created: ${file_path}" 45 | return 1 46 | fi 47 | } 48 | 49 | 50 | ### 51 | ### Create symlink 52 | ### 53 | create_link() { 54 | local src_dir="${1}" 55 | local link_name="${2}" 56 | local sub_dir= 57 | local link_from="${3}" 58 | 59 | link_name="$( printf "%q" "${link_name}" )" 60 | sub_dir="$( printf "%q" "$( eval "dirname ${link_name}" )" )" 61 | 62 | if ! eval "test -d ${src_dir}"; then 63 | printf "No such directpry: %s\\n" "${src_dir}" 64 | return 1 65 | fi 66 | # Create sub-directory if it doesn't exist 67 | if [ "${sub_dir}" != "." ]; then 68 | printf "# Create basedir: %s\\n" "${sub_dir}" 69 | run "mkdir -p ${src_dir}/${sub_dir}" 70 | fi 71 | run "cd ${src_dir} && ln -s ${link_from} ${link_name}" 72 | } 73 | -------------------------------------------------------------------------------- /tests/.lib/dir-size.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | check_dir_size() { 13 | local src= 14 | local dst= 15 | src="$( printf "%q" "${1}" )" 16 | dst="$( printf "%q" "${2}" )" 17 | 18 | src_size="$( get_dir_size_with_hardlinks "${src}" )" 19 | dst_size="$( get_dir_size_with_hardlinks "${dst}" )" 20 | 21 | if [ "${src_size}" -eq "${dst_size}" ]; then 22 | printf "[TEST] [OK] src-dir(%s) and dst-dir(%s) size match\\r\\n" "${src_size}" "${dst_size}" 23 | return 0 24 | fi 25 | printf "[TEST] [FAIL] src-dir(%s) and dst-dir(%s) size don't match: (src: %s) (dst: %s)\\r\\n" "${src_size}" "${dst_size}" "${src}" "${dst}" 26 | return 1 27 | } 28 | 29 | 30 | # ------------------------------------------------------------------------------------------------- 31 | # PRIVATE FUNCTIONS 32 | # ------------------------------------------------------------------------------------------------- 33 | 34 | ### 35 | ### Return total size of directory in bytes. 36 | ### It also counts the size of hardlinks. 37 | ### 38 | ### @param abs_path directory 39 | ### 40 | get_dir_size_with_hardlinks() { 41 | local dir= 42 | local size= 43 | dir="$( printf "%q" "${1}" )" 44 | 45 | size="$( run "cd '${dir}' && du -d0 '.' | awk '{print \$1}'" "1" "stderr" )" 46 | echo "${size}" 47 | } 48 | 49 | ### 50 | ### Return total size of directory in bytes. 51 | ### Subtract the size of any hardlinks. 52 | ### 53 | ### @param abs_path directory 54 | ### 55 | get_dir_size_without_hardlinks() { 56 | local dir= 57 | dir="$( printf "%q" "${1}" )" 58 | local suffix="${2:-}" 59 | local actual_path= 60 | local current_dir_name= 61 | local parent_dir_path= 62 | local size= 63 | 64 | 65 | # Return the actual path (in case we're in a symlink) 66 | actual_path="$( printf "%q" "$( run "cd ${dir} && pwd -P" "1" "stderr" )" )" 67 | 68 | # Get only the name of the current directory 69 | current_dir_name="$( printf "%q" "$( run "basename ${actual_path}" "1" "stderr" )" )" 70 | 71 | # Get the parent directory path 72 | parent_dir_path="$( printf "%q" "$( run "dirname ${actual_path}" "1" "stderr" )" )" 73 | 74 | 75 | size="$( run "cd ${parent_dir_path} && du -d2 2>/dev/null | grep -E '${current_dir_name}${suffix}\$' | head -1 | awk '{print \$1}'" "1" "stderr" )" 76 | echo "${size}" 77 | } 78 | -------------------------------------------------------------------------------- /tests/.lib/file-exist.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Check if source and destination file exist 14 | ### 15 | ### @param rel_path filename 16 | ### @param abs_path source directory 17 | ### @param abs_path destination directory 18 | ### 19 | check_src_dst_file_exist() { 20 | local f="${1}" 21 | local src_dir="${2}" 22 | local dst_dir="${3}" 23 | local src= 24 | local dst= 25 | 26 | file_name="$( printf "%q" "${f}" )" 27 | src="${src_dir}/${file_name}" 28 | dst="${dst_dir}/${file_name}" 29 | 30 | 31 | cmd="test -f ${src}" 32 | if ! eval "${cmd}"; then 33 | printf "[TEST] [FAIL] Source file does not exist: %s\\r\\n" "${src}" 34 | printf "%s" "$( ls "${src_dir}" )" 35 | return 1 36 | fi 37 | 38 | cmd="test -f ${dst}" 39 | if ! eval "${cmd}"; then 40 | printf "[TEST] [FAIL] Destination file does not exist: %s\\r\\n" "${dst}" 41 | printf "%s" "$( ls "${src_dir}" )" 42 | return 1 43 | fi 44 | printf "[TEST] [OK] Source and Destination files exist\\r\\n" 45 | } 46 | 47 | 48 | ### 49 | ### Check if destination file is a file 50 | ### 51 | ### @param rel_path filename 52 | ### @param abs_path destination directory 53 | ### 54 | check_dst_file_is_file() { 55 | local f="${1}" 56 | local dst_dir="${2}" 57 | local dst= 58 | 59 | file_name="$( printf "%q" "${f}" )" 60 | dst="${dst_dir}/${file_name}" 61 | 62 | cmd="test -d ${dst}" 63 | if eval "${cmd}"; then 64 | printf "[TEST] [FAIL] Destination file is a directory: %s\\r\\n" "${dst}" 65 | return 1 66 | fi 67 | 68 | cmd="test -L ${dst}" 69 | if eval "${cmd}"; then 70 | printf "[TEST] [FAIL] Destination file is a symlink: %s\\r\\n" "${dst}" 71 | return 1 72 | fi 73 | 74 | cmd="test -f ${dst}" 75 | if eval "${cmd}"; then 76 | printf "[TEST] [OK] Destination file is a regular file: %s\\r\\n" "${dst}" 77 | return 0 78 | fi 79 | 80 | printf "[TEST] [FAIL] Destination file is not a regular file: %s\\r\\n" "${dst}" 81 | return 1 82 | } 83 | 84 | 85 | ### 86 | ### Check if destination file is a symlink 87 | ### 88 | ### @param rel_path filename 89 | ### @param abs_path destination directory 90 | ### 91 | check_dst_file_is_link() { 92 | local f="${1}" 93 | local dst_dir="${2}" 94 | local dst= 95 | 96 | dst="$( printf "%q" "${dst_dir}/${f}" )" 97 | 98 | if [ -d "${dst}" ]; then 99 | printf "[TEST] [FAIL] Destination file is a directory: %s\\r\\n" "${dst}" 100 | return 1 101 | fi 102 | if [ -L "${dst}" ]; then 103 | printf "[TEST] [OK] Destination file is a symlink\\r\\n" 104 | return 105 | fi 106 | printf "[TEST] [FAIL] Destination file is not a symlink: %s\\r\\n" "${dst}" 107 | return 1 108 | } 109 | 110 | 111 | ### 112 | ### Check if source and destination file equal 113 | ### 114 | ### @param rel_path filename 115 | ### @param abs_path source directory 116 | ### @param abs_path destination directory 117 | ### 118 | check_src_dst_file_equal() { 119 | local f="${1}" 120 | local src_dir="${2}" 121 | local dst_dir="${3}" 122 | local src= 123 | local dst= 124 | 125 | src="${src_dir}/$( printf "%q" "${f}" )" 126 | dst="${dst_dir}/$( printf "%q" "${f}" )" 127 | 128 | if ! run "cmp ${src} ${dst}"; then 129 | printf "[TEST] [FAIL] Source (%s) and dest (%s) files differ\\r\\n" "${src}" "${dst}" 130 | return 1 131 | else 132 | printf "[TEST] [OK] Source and dest files are equal\\r\\n" 133 | fi 134 | } 135 | -------------------------------------------------------------------------------- /tests/.lib/file-owner.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Check src and dest file uid 14 | ### 15 | ### @param rel_path filename 16 | ### @param abs_path source directory 17 | ### @param abs_path destination directory 18 | ### 19 | check_src_dst_file_uid() { 20 | local f="${1}" 21 | local src_dir="${2}" 22 | local dst_dir="${3}" 23 | 24 | local src_uid= 25 | local dst_uid= 26 | src_uid="$( get_file_uid "${src_dir}/${f}" )" 27 | dst_uid="$( get_file_uid "${dst_dir}/${f}" )" 28 | 29 | if [ "${src_uid}" != "${dst_uid}" ]; then 30 | printf "[TEST] [FAIL] Owner uid: (%s) src and dst don't match: %s != %s\\r\\n" "${f}" "${src_uid}" "${dst_uid}" 31 | return 1 32 | else 33 | printf "[TEST] [OK] Owner uid: (%s) src and dst match: %s = %s\\r\\n" "${f}" "${src_uid}" "${dst_uid}" 34 | fi 35 | } 36 | 37 | 38 | ### 39 | ### Check src and dest file gid 40 | ### 41 | ### @param rel_path filename 42 | ### @param abs_path source directory 43 | ### @param abs_path destination directory 44 | ### 45 | check_src_dst_file_gid() { 46 | local f="${1}" 47 | local src_dir="${2}" 48 | local dst_dir="${3}" 49 | 50 | local src_gid= 51 | local dst_gid= 52 | src_gid="$( get_file_gid "${src_dir}/${f}" )" 53 | dst_gid="$( get_file_gid "${dst_dir}/${f}" )" 54 | 55 | if [ "${src_gid}" != "${dst_gid}" ]; then 56 | printf "[TEST] [FAIL] Owner gid: (%s) src and dst don't match: %s != %s\\r\\n" "${f}" "${src_gid}" "${dst_gid}" 57 | return 1 58 | else 59 | printf "[TEST] [OK] Owner gid: (%s) src and dst match: %s = %s\\r\\n" "${f}" "${src_gid}" "${dst_gid}" 60 | fi 61 | } 62 | 63 | 64 | # ------------------------------------------------------------------------------------------------- 65 | # PRIVATE FUNCTIONS 66 | # ------------------------------------------------------------------------------------------------- 67 | 68 | ### 69 | ### Get uid 70 | ### 71 | get_file_uid() { 72 | local file_path="${1}" 73 | 74 | if [ "$(uname)" = "Linux" ]; then 75 | run "stat -c '%u' '${file_path}'" "1" "stderr" 76 | else 77 | run "stat -f '%u' '${file_path}'" "1" "stderr" 78 | fi 79 | } 80 | 81 | 82 | ### 83 | ### Get gid 84 | ### 85 | get_file_gid() { 86 | local file_path="${1}" 87 | 88 | if [ "$(uname)" = "Linux" ]; then 89 | run "stat -c '%g' '${file_path}'" "1" "stderr" 90 | else 91 | run "stat -f '%g' '${file_path}'" "1" "stderr" 92 | fi 93 | } 94 | -------------------------------------------------------------------------------- /tests/.lib/file-permissions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Check destination file permission. 14 | ### 15 | ### @param rel_path filename 16 | ### @param octal source file permission 17 | ### @param octal expected file permission 18 | ### @param abs_path destination directory 19 | ### 20 | check_dst_file_perm() { 21 | local f="${1}" 22 | local src_perm="${2}" 23 | local exp_perm="${3}" 24 | local dst_perm= 25 | local dst_dir="${4}" 26 | 27 | dst_perm="$( get_file_perm "${dst_dir}/${f}" )" 28 | 29 | if [ "${exp_perm}" != "${dst_perm}" ]; then 30 | printf "[TEST] [FAIL] Permissions: %s: (src: %s) (exp: %s) (dst: %s}\\r\\n" "${f}" "${src_perm}" "${exp_perm}" "${dst_perm}" 31 | return 1 32 | else 33 | printf "[TEST] [OK] Permissions: %s: (src: %s) (exp: %s) (dst: %s}\\r\\n" "${f}" "${src_perm}" "${exp_perm}" "${dst_perm}" 34 | fi 35 | } 36 | 37 | 38 | ### 39 | ### Check source against destination file permission 40 | ### 41 | ### @param rel_path filename 42 | ### @param abs_path source directory 43 | ### @param abs_path destination directory 44 | ### 45 | check_src_dst_file_perm() { 46 | local f="${1}" 47 | local src_dir="${2}" 48 | local dst_dir="${3}" 49 | 50 | local src_perm= 51 | local dst_perm= 52 | src_perm="$( get_file_perm "${src_dir}/${f}" )" 53 | dst_perm="$( get_file_perm "${dst_dir}/${f}" )" 54 | 55 | if [ "${src_perm}" != "${dst_perm}" ]; then 56 | printf "[TEST] [FAIL] Permissions: (%s) src and dst don't match: %s != %s\\r\\n" "${f}" "${src_perm}" "${dst_perm}" 57 | return 1 58 | else 59 | printf "[TEST] [OK] Permissions: (%s) src and dst match: %s = %s\\r\\n" "${f}" "${src_perm}" "${dst_perm}" 60 | fi 61 | } 62 | 63 | 64 | # ------------------------------------------------------------------------------------------------- 65 | # PRIVATE FUNCTIONS 66 | # ------------------------------------------------------------------------------------------------- 67 | 68 | ### 69 | ### Convert one oct digit into rwx format 70 | ### 71 | oct_to_rwx() { 72 | oct="${1}" 73 | case "${oct}" in 74 | 1) echo "--x";; 75 | 2) echo "-w-";; 76 | 3) echo "-wx";; 77 | 4) echo "r--";; 78 | 5) echo "r-x";; 79 | 6) echo "rw-";; 80 | 7) echo "rwx";; 81 | esac 82 | } 83 | 84 | 85 | ### 86 | ### Convert rwx to one oct digit 87 | ### 88 | rwx_to_oct() { 89 | rwx="${1}" 90 | case "${rwx}" in 91 | --x) echo "1";; 92 | -w-) echo "2";; 93 | -wx) echo "3";; 94 | r--) echo "4";; 95 | r-x) echo "5";; 96 | rw-) echo "6";; 97 | rwx) echo "7";; 98 | esac 99 | } 100 | 101 | 102 | ### 103 | ### Get intersection (least one) between to rwx values 104 | ### 105 | get_rwx_intersect() { 106 | rwx_1="${1}" 107 | rwx_2="${2}" 108 | 109 | r="r" 110 | if [ "$( echo "${rwx_1}" | cut -c1 )" == "-" ]; then 111 | r="-" 112 | fi 113 | if [ "$( echo "${rwx_2}" | cut -c1 )" == "-" ]; then 114 | r="-" 115 | fi 116 | 117 | w="w" 118 | if [ "$( echo "${rwx_1}" | cut -c2 )" == "-" ]; then 119 | w="-" 120 | fi 121 | if [ "$( echo "${rwx_2}" | cut -c2 )" == "-" ]; then 122 | w="-" 123 | fi 124 | 125 | x="x" 126 | if [ "$( echo "${rwx_1}" | cut -c3 )" == "-" ]; then 127 | x="-" 128 | fi 129 | if [ "$( echo "${rwx_2}" | cut -c3 )" == "-" ]; then 130 | x="-" 131 | fi 132 | 133 | echo "${r}${w}${x}" 134 | } 135 | 136 | 137 | ### 138 | ### Get default directory permission based on umask 139 | ### 140 | get_default_dir_perm() { 141 | local mask 142 | mask="$( umask | sed 's/^0*//g' )" 143 | echo "$(( 777 - mask ))" 144 | } 145 | 146 | 147 | ### 148 | ### Calculate the target file permission if using --no-perms for rsync 149 | ### 150 | ### This is done by masking the current file permission with default directory umask 151 | ### 152 | get_default_dest_file_perm() { 153 | # Retrieve desired file permission in rwx 154 | file_perm="${1}" 155 | file_perm_1="$( oct_to_rwx "$(echo "${file_perm}" | cut -c1)" )" 156 | file_perm_2="$( oct_to_rwx "$(echo "${file_perm}" | cut -c2)" )" 157 | file_perm_3="$( oct_to_rwx "$(echo "${file_perm}" | cut -c3)" )" 158 | 159 | # Retrieve default directory permission in rwx 160 | dir_perm="$( get_default_dir_perm )" 161 | dir_perm_1="$( oct_to_rwx "$(echo "${dir_perm}" | cut -c1)" )" 162 | dir_perm_2="$( oct_to_rwx "$(echo "${dir_perm}" | cut -c2)" )" 163 | dir_perm_3="$( oct_to_rwx "$(echo "${dir_perm}" | cut -c3)" )" 164 | 165 | # Intersect permissions 166 | final_perm_1="$( get_rwx_intersect "${file_perm_1}" "${dir_perm_1}" )" 167 | final_perm_2="$( get_rwx_intersect "${file_perm_2}" "${dir_perm_2}" )" 168 | final_perm_3="$( get_rwx_intersect "${file_perm_3}" "${dir_perm_3}" )" 169 | 170 | # Revert to oct 171 | final_perm_1="$( rwx_to_oct "${final_perm_1}" )" 172 | final_perm_2="$( rwx_to_oct "${final_perm_2}" )" 173 | final_perm_3="$( rwx_to_oct "${final_perm_3}" )" 174 | 175 | echo "${final_perm_1}${final_perm_2}${final_perm_3}" 176 | } 177 | 178 | 179 | ### 180 | ### Get three digit octal file permissions 181 | ### 182 | get_file_perm() { 183 | local file_path="${1}" 184 | local out 185 | file_path="$( printf "%q" "${file_path}" )" 186 | 187 | if [ "$(uname)" = "Linux" ]; then 188 | out="$( run "stat -c '%a' ${file_path}" "1" "stderr" )" 189 | else 190 | out="$( run "stat -f '%A' ${file_path}" "1" "stderr" )" 191 | fi 192 | out="${out//\"/}" 193 | >&2 echo "${out}" 194 | echo "${out}" 195 | } 196 | -------------------------------------------------------------------------------- /tests/.lib/file-size.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Check source and destination file size 14 | ### 15 | ### @param rel_path filename 16 | ### @param abs_path source directory 17 | ### @param abs_path destination directory 18 | ### 19 | check_src_dst_file_size() { 20 | local f="${1}" 21 | local src_dir="${2}" 22 | local dst_dir="${3}" 23 | 24 | local src_size= 25 | local dst_size= 26 | src_size="$( get_file_size "${src_dir}/${f}" )" 27 | dst_size="$( get_file_size "${dst_dir}/${f}" )" 28 | 29 | if [ "${src_size}" != "${dst_size}" ]; then 30 | printf "[TEST] [FAIL] File size: (%s) src and dst don't match: %s != %s\\r\\n" "${f}" "${src_size}" "${dst_size}" 31 | return 1 32 | else 33 | printf "[TEST] [OK] File size: (%s) src and dst match: %s = %s\\r\\n" "${f}" "${src_size}" "${dst_size}" 34 | fi 35 | } 36 | 37 | 38 | # ------------------------------------------------------------------------------------------------- 39 | # PRIVATE FUNCTIONS 40 | # ------------------------------------------------------------------------------------------------- 41 | 42 | ### 43 | ### Get size in bytes of a file 44 | ### 45 | get_file_size() { 46 | local file_path="${1}" 47 | 48 | if [ "$(uname)" = "Linux" ]; then 49 | run "stat -c '%s' '${file_path}'" "1" "stderr" 50 | else 51 | run "stat -f '%z' '${file_path}'" "1" "stderr" 52 | fi 53 | } 54 | -------------------------------------------------------------------------------- /tests/.lib/file-time.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Check source and destination file modification time 14 | ### 15 | ### @param rel_path filename 16 | ### @param abs_path source directory 17 | ### @param abs_path destination directory 18 | ### 19 | check_src_dst_file_mod_time() { 20 | local f="${1}" 21 | local src_dir="${2}" 22 | local dst_dir="${3}" 23 | local match="1" 24 | 25 | if [ "${#}" -gt "3" ]; then 26 | match="${4}" 27 | fi 28 | 29 | 30 | local src_time= 31 | local dst_time= 32 | src_time="$( get_mod_time "${src_dir}/${f}" )" 33 | dst_time="$( get_mod_time "${dst_dir}/${f}" )" 34 | 35 | # Check that they dont match 36 | if [ "${match}" = "0" ]; then 37 | if [ "${src_time}" = "${dst_time}" ]; then 38 | printf "[TEST] [FAIL] Mod time: (%s) src and dst match: %s != %s\\r\\n" "${f}" "${src_time}" "${dst_time}" 39 | return 1 40 | else 41 | printf "[TEST] [OK] Mod time: (%s) src and dst do not match: %s = %s\\r\\n" "${f}" "${src_time}" "${dst_time}" 42 | fi 43 | # Check that they match 44 | else 45 | if [ "${src_time}" != "${dst_time}" ]; then 46 | printf "[TEST] [FAIL] Mod time: (%s) src and dst don't match: %s != %s\\r\\n" "${f}" "${src_time}" "${dst_time}" 47 | return 1 48 | else 49 | printf "[TEST] [OK] Mod time: (%s) src and dst match: %s = %s\\r\\n" "${f}" "${src_time}" "${dst_time}" 50 | fi 51 | fi 52 | } 53 | 54 | 55 | # ------------------------------------------------------------------------------------------------- 56 | # PRIVATE FUNCTIONS 57 | # ------------------------------------------------------------------------------------------------- 58 | 59 | ### 60 | ### Get modification time 61 | ### 62 | get_mod_time() { 63 | local file_path="${1}" 64 | 65 | if [ "$(uname)" = "Linux" ]; then 66 | run "stat -c '%Y' '${file_path}'" "1" "stderr" 67 | else 68 | run "stat -f '%m' '${file_path}'" "1" "stderr" 69 | fi 70 | } 71 | -------------------------------------------------------------------------------- /tests/.lib/functions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPT_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | 9 | 10 | # shellcheck disable=SC1090 11 | . "${SCRIPT_PATH}/.lib/create-source.sh" 12 | # shellcheck disable=SC1090 13 | . "${SCRIPT_PATH}/.lib/run-backup.sh" 14 | # shellcheck disable=SC1090 15 | . "${SCRIPT_PATH}/.lib/dir-size.sh" 16 | # shellcheck disable=SC1090 17 | . "${SCRIPT_PATH}/.lib/file-exist.sh" 18 | # shellcheck disable=SC1090 19 | . "${SCRIPT_PATH}/.lib/file-permissions.sh" 20 | # shellcheck disable=SC1090 21 | . "${SCRIPT_PATH}/.lib/file-size.sh" 22 | # shellcheck disable=SC1090 23 | . "${SCRIPT_PATH}/.lib/file-owner.sh" 24 | # shellcheck disable=SC1090 25 | . "${SCRIPT_PATH}/.lib/file-time.sh" 26 | # shellcheck disable=SC1090 27 | . "${SCRIPT_PATH}/.lib/print.sh" 28 | 29 | 30 | # ------------------------------------------------------------------------------------------------- 31 | # WRAPPER FUNCTIONS 32 | # ------------------------------------------------------------------------------------------------- 33 | 34 | ### 35 | ### Run command 36 | ### 37 | run() { 38 | local cmd="${1}" 39 | local verbose=1 40 | local std_out="stdout" 41 | local std_err="stderr" 42 | 43 | # be verbose? 44 | if [ "${#}" -gt "1" ]; then 45 | verbose="${2}" 46 | fi 47 | if [ "${#}" -gt "2" ]; then 48 | std_out="${3}" 49 | fi 50 | if [ "${#}" -gt "3" ]; then 51 | std_err="${4}" 52 | fi 53 | 54 | local red="\\033[0;31m" 55 | local green="\\033[0;32m" 56 | local yellow="\\033[0;33m" 57 | local reset="\\033[0m" 58 | 59 | # Print command? 60 | if [ "${verbose}" -eq "1" ]; then 61 | # stdout 62 | if [ "${std_out}" = "stdout" ]; then 63 | printf "${yellow}%s \$${reset} %s\\n" "$(whoami)" "${cmd}" 64 | # stderr 65 | else 66 | >&2 printf "${yellow}%s \$${reset} %s\\n" "$(whoami)" "${cmd}" 67 | fi 68 | fi 69 | 70 | # Set command 71 | cmd="set -e && set -u && set -o pipefail && ${cmd}" 72 | 73 | if eval "${cmd}"; then 74 | if [ "${verbose}" -eq "1" ]; then 75 | # stdout 76 | if [ "${std_out}" = "stdout" ]; then 77 | printf "${green}[%s]${reset}\\n" "OK" 78 | # stderr 79 | else 80 | >&2 printf "${green}[%s]${reset}\\n" "OK" 81 | fi 82 | fi 83 | return 0 84 | fi 85 | if [ "${verbose}" -eq "1" ]; then 86 | # stderr 87 | if [ "${std_err}" = "stderr" ]; then 88 | >&2 printf "${red}[%s]${reset}\\n" "FAIL" 89 | # stdout 90 | else 91 | printf "${red}[%s]${reset}\\n" "FAIL" 92 | fi 93 | fi 94 | return 1 95 | } 96 | 97 | 98 | ### 99 | ### Create tmp file 100 | ### 101 | create_tmp_file() { 102 | local tmp_file= 103 | 104 | if ! command -v mktemp >/dev/null 2>&1; then 105 | i=0 106 | local prefix="/tmp/timemachine" 107 | while [ -f "${prefix}-${i}.txt" ]; do 108 | i="$(( i + 1 ))" 109 | done 110 | tmp_file="${prefix}-${i}.txt" 111 | mkdir "${tmp_file}" 112 | else 113 | tmp_file="$( mktemp )" 114 | fi 115 | 116 | echo "${tmp_file}" 117 | #printf "%s" "${tmp_file}" | sed 's|/*$||' 118 | } 119 | 120 | 121 | ### 122 | ### Create tmp dir 123 | ### 124 | create_tmp_dir() { 125 | local absolute="${1:-1}" 126 | local pwd="${2:-}" 127 | local suffix="${3:-}" 128 | local tmp_dir= 129 | 130 | ### 131 | ### Create relative path tmp dir 132 | ### 133 | if [ "${absolute}" = "0" ]; then 134 | i=0 135 | while [ -d "${pwd}/.tmp/${i}${suffix}" ] || [ -f "${pwd}/.tmp/${i}${suffix}" ]; do 136 | i="$(( i + 1 ))" 137 | done 138 | tmp_dir=".tmp/${i}${suffix}" 139 | run "cd ${pwd} && mkdir -p ${tmp_dir}" "1" "stderr" "stderr" 140 | echo "${tmp_dir}" 141 | return 142 | fi 143 | 144 | ### 145 | ### Create absolute path tmp dir 146 | ### 147 | # NOTE: MacOS does not have 'mktemp --suffix', so we're using our own version 148 | i=0 149 | local prefix="/tmp/timemachine" 150 | while [ -d "${prefix}-${i}${suffix}" ] || [ -f "${prefix}-${i}${suffix}" ]; do 151 | i="$(( i + 1 ))" 152 | done 153 | tmp_dir="$( printf "%q" "${prefix}-${i}${suffix}" )" 154 | run "mkdir -p ${tmp_dir}" "1" "stderr" "stderr" 155 | echo "${tmp_dir}" 156 | } 157 | -------------------------------------------------------------------------------- /tests/.lib/print.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Print main section 14 | ### 15 | print_section() { 16 | local text="${1}" 17 | printf "\\r\\n" 18 | printf '@%.0s' {1..110}; 19 | printf "\\r\\n" 20 | printf '@%.0s' {1..110}; 21 | printf "\\r\\n" 22 | 23 | printf "@@@@@@\\r\\n" 24 | printf "@@@@@@ %s\\r\\n" "${text}" 25 | printf "@@@@@@\\r\\n" 26 | 27 | printf '@%.0s' {1..110}; 28 | printf "\\r\\n" 29 | printf '@%.0s' {1..110}; 30 | printf "\\r\\n" 31 | printf "\\r\\n" 32 | } 33 | 34 | 35 | ### 36 | ### Print headline 37 | ### 38 | print_headline() { 39 | local text="${1}" 40 | 41 | printf "\\r\\n" 42 | printf '### ' 43 | printf '#%.0s' {1..96}; 44 | printf "\\r\\n" 45 | 46 | printf "###\\r\\n" 47 | printf "### %s\\r\\n" "${text}" 48 | printf "###\\r\\n" 49 | 50 | printf '### ' 51 | printf '#%.0s' {1..96}; 52 | printf "\\r\\n" 53 | printf "\\r\\n" 54 | } 55 | 56 | 57 | ### 58 | ### Print sub headline 59 | ### 60 | print_subline() { 61 | local text="${1}" 62 | 63 | printf -- '-%.0s' {1..80}; 64 | printf "\\r\\n" 65 | printf " %s\\r\\n" "${text}" 66 | printf -- '-%.0s' {1..80}; 67 | printf "\\r\\n" 68 | } 69 | -------------------------------------------------------------------------------- /tests/.lib/run-backup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | 8 | # ------------------------------------------------------------------------------------------------- 9 | # PUBLIC FUNCTIONS 10 | # ------------------------------------------------------------------------------------------------- 11 | 12 | ### 13 | ### Run backup 14 | ### 15 | run_backup() { 16 | local timemachine_path="${1}" 17 | local src_dir="${2}" 18 | local dst_dir="${3}" 19 | local rsync_args="${4}" 20 | local backup_type="${5}" 21 | local pwd="${6:-/}" 22 | 23 | local out 24 | local err 25 | 26 | rsync_args="${rsync_args} --progress --verbose" 27 | timemachine_path="$( printf "%q" "${timemachine_path}" )" 28 | 29 | out="$( create_tmp_file )" 30 | err="$( create_tmp_file )" 31 | 32 | ### 33 | ### Give 2 seconds time for a new unique directory name (second based) to be created 34 | ### 35 | sleep 2 36 | 37 | ### 38 | ### Run and check for failure 39 | ### 40 | if ! run "cd \"${pwd}\" && ${timemachine_path} -d ${src_dir} ${dst_dir} ${rsync_args} > \"${out}\" 2> \"${err}\""; then 41 | printf "[TEST] [FAIL] Run failed.\\r\\n" 42 | cat "${out}" 43 | cat "${err}" 44 | rm "${out}" 45 | rm "${err}" 46 | return 1 47 | fi 48 | cat "${out}" 49 | echo 50 | 51 | ### 52 | ### Check for warnings 53 | ### 54 | if [ -s "${err}" ]; then 55 | printf "[TEST] [FAIL] Warnings detected.\\r\\n" 56 | printf "Warnings:\\r\\n----------\\r\\n%s\\r\\n" "$( cat "${err}" )" 57 | rm "${out}" 58 | rm "${err}" 59 | return 1 60 | fi 61 | printf "[TEST] [OK] No warnings detected.\\r\\n" 62 | 63 | ### 64 | ### Check for backup type 65 | ### 66 | if ! grep "Starting ${backup_type} backup" "${out}" >/dev/null; then 67 | printf "[TEST] [FAIL] Not a '%s' backup\\r\\n" "${backup_type}" 68 | rm "${out}" 69 | rm "${err}" 70 | return 1 71 | fi 72 | printf "[TEST] [OK] Backup type: '%s' backup.\\r\\n" "${backup_type}" 73 | 74 | ### 75 | ### Check for existing latest symlink 76 | ### 77 | if ! eval "test -L ${pwd}/${dst_dir}/current"; then 78 | printf "[TEST] [FAIL] No latest symlink available: %s\\r\\n" "${pwd}/${dst_dir}/current" 79 | rm "${out}" 80 | rm "${err}" 81 | return 1 82 | fi 83 | printf "[TEST] [OK] Latest symlink available: %s\\r\\n" "${pwd}/${dst_dir}/current" 84 | 85 | ### 86 | ### Check partial backup .inprogress directory 87 | ### 88 | if eval "test -d ${pwd}/${dst_dir}/current/.inprogress"; then 89 | printf "[TEST] [FAIL] Undeleted '.inprogress' directory found: %s\\r\\n" "${pwd}/${dst_dir}/current/.inprogress" 90 | rm "${out}" 91 | rm "${err}" 92 | return 1 93 | fi 94 | printf "[TEST] [OK] No '.inprogress' directory found\\r\\n" 95 | 96 | ### 97 | ### Remove artifacts 98 | ### 99 | rm "${out}" 100 | rm "${err}" 101 | } 102 | 103 | 104 | ### 105 | ### Run backup over SSH via Docker 106 | ### 107 | run_remote_backup() { 108 | local docker_client_name="${1}" 109 | local docker_server_name="${2}" 110 | local timemachine_path="${3}" 111 | local timemachine_args="${4}" 112 | local src_dir="${5}" 113 | local ssh_string="${6}" 114 | local dst_dir="${7}" 115 | local rsync_args="${8}" 116 | local backup_type="${9}" 117 | local pwd="${10:-}" 118 | 119 | local out 120 | local err 121 | 122 | out="$( create_tmp_file )" 123 | err="$( create_tmp_file )" 124 | exc="$( create_tmp_file )" 125 | 126 | ### 127 | ### Give 2 seconds time for a new unique directory name (second based) to be created 128 | ### 129 | sleep 2 130 | 131 | # Create execution file 132 | { 133 | printf "#!/bin/bash\\n"; 134 | printf "SRC='%s'\\n" "${src_dir}"; 135 | printf "DST='%s'\\n" "${dst_dir}"; 136 | printf "BIN=\"%s\"\\n" "${timemachine_path}"; 137 | printf "ARG=\"%s\"\\n" "${timemachine_args}"; 138 | printf "SSH=\"%s\"\\n" "${ssh_string}"; 139 | printf "RAR=\"%s\"\\n" "${rsync_args}"; 140 | printf "bash \${BIN} -d \${ARG} \"\${SRC}\" \${SSH}:\"\${DST}\" \${RAR}\\n"; 141 | } > "${exc}" 142 | chmod +x "${exc}" 143 | docker cp "${exc}" "${docker_client_name}:/run.sh" 144 | #cat "${exc}" 145 | ### 146 | ### Run and check for failure 147 | ### 148 | if ! run "docker exec ${docker_client_name} /run.sh > \"${out}\" 2> \"${err}\""; then 149 | #if ! run "docker exec ${docker_client_name} ${timemachine_path} -d ${timemachine_args} ${src_dir} ${ssh_string}:${dst_dir} ${rsync_args} > \"${out}\" 2> \"${err}\""; then 150 | printf "[TEST] [FAIL] Run failed.\\r\\n" 151 | cat "${out}" 152 | cat "${err}" 153 | rm "${out}" 154 | rm "${err}" 155 | run "docker rm -f ${docker_client_name}" || true 156 | run "docker rm -f ${docker_server_name}" || true 157 | return 1 158 | fi 159 | cat "${out}" 160 | echo 161 | 162 | ### 163 | ### Check for warnings 164 | ### 165 | if [ -s "${err}" ]; then 166 | printf "[TEST] [FAIL] Warnings detected.\\r\\n" 167 | printf "Warnings:\\r\\n----------\\r\\n%s\\r\\n" "$( cat "${err}" )" 168 | rm "${out}" 169 | rm "${err}" 170 | run "docker rm -f ${docker_client_name}" || true 171 | run "docker rm -f ${docker_server_name}" || true 172 | return 1 173 | fi 174 | printf "[TEST] [OK] No warnings detected.\\r\\n" 175 | 176 | ### 177 | ### Check for backup type 178 | ### 179 | if ! grep "Starting ${backup_type} backup" "${out}" >/dev/null; then 180 | printf "[TEST] [FAIL] Not a '%s' backup\\r\\n" "${backup_type}" 181 | rm "${out}" 182 | rm "${err}" 183 | run "docker rm -f ${docker_client_name}" || true 184 | run "docker rm -f ${docker_server_name}" || true 185 | return 1 186 | fi 187 | printf "[TEST] [OK] Backup type: '%s' backup.\\r\\n" "${backup_type}" 188 | 189 | ### 190 | ### Check for existing latest symlink 191 | ### 192 | if ! docker exec "${docker_server_name}" test -L "${pwd}${dst_dir}/current"; then 193 | printf "[TEST] [FAIL] No latest symlink available: %s\\r\\n" "${ssh_string}:${pwd}${dst_dir}/current" 194 | rm "${out}" 195 | rm "${err}" 196 | run "docker rm -f ${docker_client_name}" || true 197 | run "docker rm -f ${docker_server_name}" || true 198 | return 1 199 | fi 200 | printf "[TEST] [OK] Latest symlink available: %s\\r\\n" "${ssh_string}:${pwd}${dst_dir}/current" 201 | 202 | ### 203 | ### Check partial backup .inprogress directory 204 | ### 205 | if docker exec "${docker_server_name}" test -d "${pwd}${dst_dir}/current/.inprogress"; then 206 | printf "[TEST] [FAIL] Undeleted '.inprogress' directory found: %s\\r\\n" "${ssh_string}:${pwd}${dst_dir}/current/.inprogress" 207 | rm "${out}" 208 | rm "${err}" 209 | run "docker rm -f ${docker_client_name}" || true 210 | run "docker rm -f ${docker_server_name}" || true 211 | return 1 212 | fi 213 | printf "[TEST] [OK] No '.inprogress' directory found\\r\\n" 214 | 215 | ### 216 | ### Remove artifacts 217 | ### 218 | rm "${out}" 219 | rm "${err}" 220 | } 221 | -------------------------------------------------------------------------------- /tests/01-run-local-default-abs-noslash-noslash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (noslash noslash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 104 | } 105 | 106 | check_dir() { 107 | local src="${1}" 108 | local dst="${2}" 109 | local destination= 110 | destination="${dst}/current/$(basename "${src}")" 111 | 112 | check_dir_size "${src}" "${destination}" 113 | } 114 | 115 | check_backup() { 116 | local src="${1}" 117 | local dst="${2}" 118 | local backup1="${3}" 119 | local backup2="${4}" 120 | 121 | local src_actual_size 122 | local dst_actual_size 123 | local backup1_actual_size 124 | local backup2_actual_size 125 | 126 | print_subline "Check incremental Backup" 127 | 128 | backup1_actual_size="$( get_dir_size_without_hardlinks "${backup1}" "/$(basename "${src}")" )" 129 | backup2_actual_size="$( get_dir_size_without_hardlinks "${backup2}" "/$(basename "${src}")" )" 130 | if [ "${backup1_actual_size}" -eq "${backup2_actual_size}" ]; then 131 | printf "[TEST] [FAIL] Incremental: inital backup (%s) and incremental backup (%s) disk sizes are equal\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 132 | exit 1 133 | fi 134 | printf "[TEST] [OK] Incremental: inital backup (%s) and incremental backup (%s) disk sizes differ\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 135 | 136 | 137 | print_subline "Check incremental Backup after deleting initial full backup" 138 | 139 | run "rm -rf '${backup1}'" 140 | src_actual_size="$( get_dir_size_with_hardlinks "${src}" )" 141 | dst_actual_size="$( get_dir_size_without_hardlinks "${dst}/current/" "/$(basename "${src}")" )" 142 | 143 | if [ "${src_actual_size}" -ne "${dst_actual_size}" ]; then 144 | printf "[TEST] [FAIL] Incremental Backup: src-dir(%s) size is not equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 145 | exit 1 146 | fi 147 | printf "[TEST] [OK] Incremental Backup: src-dir(%s) size is equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 148 | } 149 | 150 | 151 | ### ################################################################################################ 152 | ### ################################################################################################ 153 | ### 154 | ### Run backup (Round 1) 155 | ### 156 | ### ################################################################################################ 157 | ### ################################################################################################ 158 | 159 | print_headline "Backup (Round 1)" 160 | 161 | print_subline "Run Backup" 162 | run_backup \ 163 | "${SCRIPTPATH}/../timemachine" \ 164 | "${SRC_DIR}" \ 165 | "${DST_DIR}" \ 166 | "${RSYNC_ARGS}" \ 167 | "full" 168 | 169 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 170 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 171 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 172 | 173 | check_link "${LINK1_NAME}" 174 | check_link "${LINK2_NAME}" 175 | check_link "${LINK3_NAME}" 176 | 177 | check_dir "${SRC_DIR}" "${DST_DIR}" 178 | 179 | BACKUP_PATH_1="$( cd "${DST_DIR}/current/" && pwd -P )" 180 | 181 | 182 | ### ################################################################################################ 183 | ### ################################################################################################ 184 | ### 185 | ### Run backup (Round 2) 186 | ### 187 | ### ################################################################################################ 188 | ### ################################################################################################ 189 | 190 | print_headline "Backup (Round 2)" 191 | 192 | print_subline "Run Backup" 193 | run_backup \ 194 | "${SCRIPTPATH}/../timemachine" \ 195 | "${SRC_DIR}" \ 196 | "${DST_DIR}" \ 197 | "${RSYNC_ARGS}" \ 198 | "incremental" 199 | 200 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 201 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 202 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 203 | 204 | check_link "${LINK1_NAME}" 205 | check_link "${LINK2_NAME}" 206 | check_link "${LINK3_NAME}" 207 | 208 | check_dir "${SRC_DIR}" "${DST_DIR}" 209 | 210 | BACKUP_PATH_2="$( cd "${DST_DIR}/current/" && pwd -P )" 211 | 212 | 213 | ### ################################################################################################ 214 | ### ################################################################################################ 215 | ### 216 | ### Validate Backups 217 | ### 218 | ### ################################################################################################ 219 | ### ################################################################################################ 220 | 221 | print_headline "Validate Backups" 222 | 223 | check_backup \ 224 | "${SRC_DIR}" \ 225 | "${DST_DIR}" \ 226 | "${BACKUP_PATH_1}" \ 227 | "${BACKUP_PATH_2}" 228 | -------------------------------------------------------------------------------- /tests/01-run-local-default-abs-noslash-slash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (noslash slash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 104 | } 105 | 106 | check_dir() { 107 | local src="${1}" 108 | local dst="${2}" 109 | local destination= 110 | destination="${dst}/current/$(basename "${src}")" 111 | 112 | check_dir_size "${src}" "${destination}" 113 | } 114 | 115 | check_backup() { 116 | local src="${1}" 117 | local dst="${2}" 118 | local backup1="${3}" 119 | local backup2="${4}" 120 | 121 | local src_actual_size 122 | local dst_actual_size 123 | local backup1_actual_size 124 | local backup2_actual_size 125 | 126 | print_subline "Check incremental Backup" 127 | 128 | backup1_actual_size="$( get_dir_size_without_hardlinks "${backup1}" "/$(basename "${src}")" )" 129 | backup2_actual_size="$( get_dir_size_without_hardlinks "${backup2}" "/$(basename "${src}")" )" 130 | if [ "${backup1_actual_size}" -eq "${backup2_actual_size}" ]; then 131 | printf "[TEST] [FAIL] Incremental: inital backup (%s) and incremental backup (%s) disk sizes are equal\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 132 | exit 1 133 | fi 134 | printf "[TEST] [OK] Incremental: inital backup (%s) and incremental backup (%s) disk sizes differ\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 135 | 136 | 137 | print_subline "Check incremental Backup after deleting initial full backup" 138 | 139 | run "rm -rf '${backup1}'" 140 | src_actual_size="$( get_dir_size_with_hardlinks "${src}" )" 141 | dst_actual_size="$( get_dir_size_without_hardlinks "${dst}/current/" "/$(basename "${src}")" )" 142 | 143 | if [ "${src_actual_size}" -ne "${dst_actual_size}" ]; then 144 | printf "[TEST] [FAIL] Incremental Backup: src-dir(%s) size is not equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 145 | exit 1 146 | fi 147 | printf "[TEST] [OK] Incremental Backup: src-dir(%s) size is equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 148 | } 149 | 150 | 151 | ### ################################################################################################ 152 | ### ################################################################################################ 153 | ### 154 | ### Run backup (Round 1) 155 | ### 156 | ### ################################################################################################ 157 | ### ################################################################################################ 158 | 159 | print_headline "Backup (Round 1)" 160 | 161 | print_subline "Run Backup" 162 | run_backup \ 163 | "${SCRIPTPATH}/../timemachine" \ 164 | "${SRC_DIR}" \ 165 | "${DST_DIR}/" \ 166 | "${RSYNC_ARGS}" \ 167 | "full" 168 | 169 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 170 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 171 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 172 | 173 | check_link "${LINK1_NAME}" 174 | check_link "${LINK2_NAME}" 175 | check_link "${LINK3_NAME}" 176 | 177 | check_dir "${SRC_DIR}" "${DST_DIR}" 178 | 179 | BACKUP_PATH_1="$( cd "${DST_DIR}/current/" && pwd -P )" 180 | 181 | 182 | ### ################################################################################################ 183 | ### ################################################################################################ 184 | ### 185 | ### Run backup (Round 2) 186 | ### 187 | ### ################################################################################################ 188 | ### ################################################################################################ 189 | 190 | print_headline "Backup (Round 2)" 191 | 192 | print_subline "Run Backup" 193 | run_backup \ 194 | "${SCRIPTPATH}/../timemachine" \ 195 | "${SRC_DIR}" \ 196 | "${DST_DIR}/" \ 197 | "${RSYNC_ARGS}" \ 198 | "incremental" 199 | 200 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 201 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 202 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 203 | 204 | check_link "${LINK1_NAME}" 205 | check_link "${LINK2_NAME}" 206 | check_link "${LINK3_NAME}" 207 | 208 | check_dir "${SRC_DIR}" "${DST_DIR}" 209 | 210 | BACKUP_PATH_2="$( cd "${DST_DIR}/current/" && pwd -P )" 211 | 212 | 213 | ### ################################################################################################ 214 | ### ################################################################################################ 215 | ### 216 | ### Validate Backups 217 | ### 218 | ### ################################################################################################ 219 | ### ################################################################################################ 220 | 221 | print_headline "Validate Backups" 222 | 223 | check_backup \ 224 | "${SRC_DIR}" \ 225 | "${DST_DIR}" \ 226 | "${BACKUP_PATH_1}" \ 227 | "${BACKUP_PATH_2}" 228 | -------------------------------------------------------------------------------- /tests/01-run-local-default-abs-slash-noslash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (slash noslash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${DST_DIR}/current" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${DST_DIR}/current" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 104 | } 105 | 106 | check_dir() { 107 | local src="${1}" 108 | local dst="${2}" 109 | local destination= 110 | destination="${dst}/current" 111 | 112 | check_dir_size "${src}" "${destination}" 113 | } 114 | 115 | check_backup() { 116 | local src="${1}" 117 | local dst="${2}" 118 | local backup1="${3}" 119 | local backup2="${4}" 120 | 121 | local src_actual_size 122 | local dst_actual_size 123 | local backup1_actual_size 124 | local backup2_actual_size 125 | 126 | print_subline "Check incremental Backup" 127 | 128 | backup1_actual_size="$( get_dir_size_without_hardlinks "${backup1}" )" 129 | backup2_actual_size="$( get_dir_size_without_hardlinks "${backup2}" )" 130 | if [ "${backup1_actual_size}" -eq "${backup2_actual_size}" ]; then 131 | printf "[TEST] [FAIL] Incremental: inital backup (%s) and incremental backup (%s) disk sizes are equal\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 132 | exit 1 133 | fi 134 | printf "[TEST] [OK] Incremental: inital backup (%s) and incremental backup (%s) disk sizes differ\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 135 | 136 | 137 | print_subline "Check incremental Backup after deleting initial full backup" 138 | 139 | run "rm -rf '${backup1}'" 140 | src_actual_size="$( get_dir_size_with_hardlinks "${src}" )" 141 | dst_actual_size="$( get_dir_size_without_hardlinks "${dst}/current/" )" 142 | 143 | if [ "${src_actual_size}" -ne "${dst_actual_size}" ]; then 144 | printf "[TEST] [FAIL] Incremental Backup: src-dir(%s) size is not equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 145 | exit 1 146 | fi 147 | printf "[TEST] [OK] Incremental Backup: src-dir(%s) size is equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 148 | } 149 | 150 | 151 | ### ################################################################################################ 152 | ### ################################################################################################ 153 | ### 154 | ### Run backup (Round 1) 155 | ### 156 | ### ################################################################################################ 157 | ### ################################################################################################ 158 | 159 | print_headline "Backup (Round 1)" 160 | 161 | print_subline "Run Backup" 162 | run_backup \ 163 | "${SCRIPTPATH}/../timemachine" \ 164 | "${SRC_DIR}/" \ 165 | "${DST_DIR}" \ 166 | "${RSYNC_ARGS}" \ 167 | "full" 168 | 169 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 170 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 171 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 172 | 173 | check_link "${LINK1_NAME}" 174 | check_link "${LINK2_NAME}" 175 | check_link "${LINK3_NAME}" 176 | 177 | check_dir "${SRC_DIR}" "${DST_DIR}" 178 | 179 | BACKUP_PATH_1="$( cd "${DST_DIR}/current/" && pwd -P )" 180 | 181 | 182 | ### ################################################################################################ 183 | ### ################################################################################################ 184 | ### 185 | ### Run backup (Round 2) 186 | ### 187 | ### ################################################################################################ 188 | ### ################################################################################################ 189 | 190 | print_headline "Backup (Round 2)" 191 | 192 | print_subline "Run Backup" 193 | run_backup \ 194 | "${SCRIPTPATH}/../timemachine" \ 195 | "${SRC_DIR}/" \ 196 | "${DST_DIR}" \ 197 | "${RSYNC_ARGS}" \ 198 | "incremental" 199 | 200 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 201 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 202 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 203 | 204 | check_link "${LINK1_NAME}" 205 | check_link "${LINK2_NAME}" 206 | check_link "${LINK3_NAME}" 207 | 208 | check_dir "${SRC_DIR}" "${DST_DIR}" 209 | 210 | BACKUP_PATH_2="$( cd "${DST_DIR}/current/" && pwd -P )" 211 | 212 | 213 | ### ################################################################################################ 214 | ### ################################################################################################ 215 | ### 216 | ### Validate Backups 217 | ### 218 | ### ################################################################################################ 219 | ### ################################################################################################ 220 | 221 | print_headline "Validate Backups" 222 | 223 | check_backup \ 224 | "${SRC_DIR}" \ 225 | "${DST_DIR}" \ 226 | "${BACKUP_PATH_1}" \ 227 | "${BACKUP_PATH_2}" 228 | -------------------------------------------------------------------------------- /tests/01-run-local-default-abs-slash-slash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (slash slash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${DST_DIR}/current" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${DST_DIR}/current" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 104 | } 105 | 106 | check_dir() { 107 | local src="${1}" 108 | local dst="${2}" 109 | local destination= 110 | destination="${dst}/current" 111 | 112 | check_dir_size "${src}" "${destination}" 113 | } 114 | 115 | check_backup() { 116 | local src="${1}" 117 | local dst="${2}" 118 | local backup1="${3}" 119 | local backup2="${4}" 120 | 121 | local src_actual_size 122 | local dst_actual_size 123 | local backup1_actual_size 124 | local backup2_actual_size 125 | 126 | print_subline "Check incremental Backup" 127 | 128 | backup1_actual_size="$( get_dir_size_without_hardlinks "${backup1}" )" 129 | backup2_actual_size="$( get_dir_size_without_hardlinks "${backup2}" )" 130 | if [ "${backup1_actual_size}" -eq "${backup2_actual_size}" ]; then 131 | printf "[TEST] [FAIL] Incremental: inital backup (%s) and incremental backup (%s) disk sizes are equal\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 132 | exit 1 133 | fi 134 | printf "[TEST] [OK] Incremental: inital backup (%s) and incremental backup (%s) disk sizes differ\\r\\n" "${backup1_actual_size}" "${backup2_actual_size}" 135 | 136 | 137 | print_subline "Check incremental Backup after deleting initial full backup" 138 | 139 | run "rm -rf '${backup1}'" 140 | src_actual_size="$( get_dir_size_with_hardlinks "${src}" )" 141 | dst_actual_size="$( get_dir_size_without_hardlinks "${dst}/current/" )" 142 | 143 | if [ "${src_actual_size}" -ne "${dst_actual_size}" ]; then 144 | printf "[TEST] [FAIL] Incremental Backup: src-dir(%s) size is not equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 145 | exit 1 146 | fi 147 | printf "[TEST] [OK] Incremental Backup: src-dir(%s) size is equal to dst-dir(%s)\\r\\n" "${src_actual_size}" "${dst_actual_size}" 148 | } 149 | 150 | 151 | ### ################################################################################################ 152 | ### ################################################################################################ 153 | ### 154 | ### Run backup (Round 1) 155 | ### 156 | ### ################################################################################################ 157 | ### ################################################################################################ 158 | 159 | print_headline "Backup (Round 1)" 160 | 161 | print_subline "Run Backup" 162 | run_backup \ 163 | "${SCRIPTPATH}/../timemachine" \ 164 | "${SRC_DIR}/" \ 165 | "${DST_DIR}/" \ 166 | "${RSYNC_ARGS}" \ 167 | "full" 168 | 169 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 170 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 171 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 172 | 173 | check_link "${LINK1_NAME}" 174 | check_link "${LINK2_NAME}" 175 | check_link "${LINK3_NAME}" 176 | 177 | check_dir "${SRC_DIR}" "${DST_DIR}" 178 | 179 | BACKUP_PATH_1="$( cd "${DST_DIR}/current/" && pwd -P )" 180 | 181 | 182 | ### ################################################################################################ 183 | ### ################################################################################################ 184 | ### 185 | ### Run backup (Round 2) 186 | ### 187 | ### ################################################################################################ 188 | ### ################################################################################################ 189 | 190 | print_headline "Backup (Round 2)" 191 | 192 | print_subline "Run Backup" 193 | run_backup \ 194 | "${SCRIPTPATH}/../timemachine" \ 195 | "${SRC_DIR}/" \ 196 | "${DST_DIR}/" \ 197 | "${RSYNC_ARGS}" \ 198 | "incremental" 199 | 200 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 201 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 202 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 203 | 204 | check_link "${LINK1_NAME}" 205 | check_link "${LINK2_NAME}" 206 | check_link "${LINK3_NAME}" 207 | 208 | check_dir "${SRC_DIR}" "${DST_DIR}" 209 | 210 | BACKUP_PATH_2="$( cd "${DST_DIR}/current/" && pwd -P )" 211 | 212 | 213 | ### ################################################################################################ 214 | ### ################################################################################################ 215 | ### 216 | ### Validate Backups 217 | ### 218 | ### ################################################################################################ 219 | ### ################################################################################################ 220 | 221 | print_headline "Validate Backups" 222 | 223 | check_backup \ 224 | "${SRC_DIR}" \ 225 | "${DST_DIR}" \ 226 | "${BACKUP_PATH_1}" \ 227 | "${BACKUP_PATH_2}" 228 | -------------------------------------------------------------------------------- /tests/02-run-local-default-rel-noslash-noslash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (noslash noslash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 34 | DST_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${SCRIPTPATH}/../${DST_DIR}/current/$(basename "${SRC_DIR}")" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${SCRIPTPATH}/../${DST_DIR}/current/$(basename "${SRC_DIR}")" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 104 | } 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_backup \ 119 | "${SCRIPTPATH}/../timemachine" \ 120 | "${SRC_DIR}" \ 121 | "${DST_DIR}" \ 122 | "${RSYNC_ARGS}" \ 123 | "full" \ 124 | "${SCRIPTPATH}/.." 125 | 126 | # TODO: check for .inprogress 127 | # TODO: add --append-verify (and check for rsync version >= 3) 128 | 129 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 130 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 131 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | check_link "${LINK1_NAME}" 134 | check_link "${LINK2_NAME}" 135 | check_link "${LINK3_NAME}" 136 | 137 | 138 | ### ################################################################################################ 139 | ### ################################################################################################ 140 | ### 141 | ### Run backup (Round 2) 142 | ### 143 | ### ################################################################################################ 144 | ### ################################################################################################ 145 | 146 | print_headline "Backup (Round 2)" 147 | 148 | print_subline "Run Backup" 149 | run_backup \ 150 | "${SCRIPTPATH}/../timemachine" \ 151 | "${SRC_DIR}" \ 152 | "${DST_DIR}" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" \ 155 | "${SCRIPTPATH}/.." 156 | 157 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 158 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 159 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 160 | 161 | check_link "${LINK1_NAME}" 162 | check_link "${LINK2_NAME}" 163 | check_link "${LINK3_NAME}" 164 | -------------------------------------------------------------------------------- /tests/02-run-local-default-rel-noslash-slash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (noslash slash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 34 | DST_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${SCRIPTPATH}/../${DST_DIR}/current/$(basename "${SRC_DIR}")" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${SCRIPTPATH}/../${DST_DIR}/current/$(basename "${SRC_DIR}")" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 104 | } 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_backup \ 119 | "${SCRIPTPATH}/../timemachine" \ 120 | "${SRC_DIR}" \ 121 | "${DST_DIR}/" \ 122 | "${RSYNC_ARGS}" \ 123 | "full" \ 124 | "${SCRIPTPATH}/.." 125 | 126 | # TODO: check for .inprogress 127 | # TODO: add --append-verify (and check for rsync version >= 3) 128 | 129 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 130 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 131 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | check_link "${LINK1_NAME}" 134 | check_link "${LINK2_NAME}" 135 | check_link "${LINK3_NAME}" 136 | 137 | 138 | ### ################################################################################################ 139 | ### ################################################################################################ 140 | ### 141 | ### Run backup (Round 2) 142 | ### 143 | ### ################################################################################################ 144 | ### ################################################################################################ 145 | 146 | print_headline "Backup (Round 2)" 147 | 148 | print_subline "Run Backup" 149 | run_backup \ 150 | "${SCRIPTPATH}/../timemachine" \ 151 | "${SRC_DIR}" \ 152 | "${DST_DIR}/" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" \ 155 | "${SCRIPTPATH}/.." 156 | 157 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 158 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 159 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 160 | 161 | check_link "${LINK1_NAME}" 162 | check_link "${LINK2_NAME}" 163 | check_link "${LINK3_NAME}" 164 | -------------------------------------------------------------------------------- /tests/02-run-local-default-rel-slash-noslash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (slash noslash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 34 | DST_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${SCRIPTPATH}/../${DST_DIR}/current" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${SCRIPTPATH}/../${DST_DIR}/current" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 104 | } 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_backup \ 119 | "${SCRIPTPATH}/../timemachine" \ 120 | "${SRC_DIR}/" \ 121 | "${DST_DIR}" \ 122 | "${RSYNC_ARGS}" \ 123 | "full" \ 124 | "${SCRIPTPATH}/.." 125 | 126 | # TODO: check for .inprogress 127 | # TODO: add --append-verify (and check for rsync version >= 3) 128 | 129 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 130 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 131 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | check_link "${LINK1_NAME}" 134 | check_link "${LINK2_NAME}" 135 | check_link "${LINK3_NAME}" 136 | 137 | 138 | ### ################################################################################################ 139 | ### ################################################################################################ 140 | ### 141 | ### Run backup (Round 2) 142 | ### 143 | ### ################################################################################################ 144 | ### ################################################################################################ 145 | 146 | print_headline "Backup (Round 2)" 147 | 148 | print_subline "Run Backup" 149 | run_backup \ 150 | "${SCRIPTPATH}/../timemachine" \ 151 | "${SRC_DIR}/" \ 152 | "${DST_DIR}" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" \ 155 | "${SCRIPTPATH}/.." 156 | 157 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 158 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 159 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 160 | 161 | check_link "${LINK1_NAME}" 162 | check_link "${LINK2_NAME}" 163 | check_link "${LINK3_NAME}" 164 | -------------------------------------------------------------------------------- /tests/02-run-local-default-rel-slash-slash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="" 17 | 18 | print_section "01 Default (slash slash)" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 34 | DST_DIR="$( create_tmp_dir "0" "${SCRIPTPATH}/.." )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SCRIPTPATH}/../${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SCRIPTPATH}/../${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | sleep 2 64 | 65 | 66 | ### ################################################################################################ 67 | ### ################################################################################################ 68 | ### 69 | ### DEFINE CHECKS 70 | ### 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | 74 | check_file() { 75 | local file="${1}" 76 | local perm="${2}" 77 | local destination= 78 | destination="${SCRIPTPATH}/../${DST_DIR}/current" 79 | 80 | print_subline "Validate ${file}" 81 | 82 | check_dst_file_is_file "${file}" "${destination}" 83 | 84 | check_src_dst_file_exist "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 85 | check_src_dst_file_equal "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 86 | 87 | check_dst_file_perm "${file}" "${perm}" "${perm}" "${destination}" 88 | check_src_dst_file_perm "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 89 | check_src_dst_file_size "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 90 | check_src_dst_file_mod_time "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 91 | check_src_dst_file_uid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 92 | check_src_dst_file_gid "${file}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 93 | } 94 | 95 | check_link() { 96 | local link="${1}" 97 | local destination= 98 | destination="${SCRIPTPATH}/../${DST_DIR}/current" 99 | 100 | print_subline "Validate ${link}" 101 | check_src_dst_file_exist "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 102 | check_dst_file_is_link "${link}" "${destination}" 103 | check_src_dst_file_equal "${link}" "${SCRIPTPATH}/../${SRC_DIR}" "${destination}" 104 | } 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_backup \ 119 | "${SCRIPTPATH}/../timemachine" \ 120 | "${SRC_DIR}/" \ 121 | "${DST_DIR}/" \ 122 | "${RSYNC_ARGS}" \ 123 | "full" \ 124 | "${SCRIPTPATH}/.." 125 | 126 | # TODO: check for .inprogress 127 | # TODO: add --append-verify (and check for rsync version >= 3) 128 | 129 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 130 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 131 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | check_link "${LINK1_NAME}" 134 | check_link "${LINK2_NAME}" 135 | check_link "${LINK3_NAME}" 136 | 137 | 138 | ### ################################################################################################ 139 | ### ################################################################################################ 140 | ### 141 | ### Run backup (Round 2) 142 | ### 143 | ### ################################################################################################ 144 | ### ################################################################################################ 145 | 146 | print_headline "Backup (Round 2)" 147 | 148 | print_subline "Run Backup" 149 | run_backup \ 150 | "${SCRIPTPATH}/../timemachine" \ 151 | "${SRC_DIR}/" \ 152 | "${DST_DIR}/" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" \ 155 | "${SCRIPTPATH}/.." 156 | 157 | check_file "${FILE1_NAME}" "${FILE1_PERM}" 158 | check_file "${FILE2_NAME}" "${FILE2_PERM}" 159 | check_file "${FILE3_NAME}" "${FILE3_PERM}" 160 | 161 | check_link "${LINK1_NAME}" 162 | check_link "${LINK2_NAME}" 163 | check_link "${LINK3_NAME}" 164 | -------------------------------------------------------------------------------- /tests/03-run-local-no_perms.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="-- --no-perms" 17 | 18 | print_section "03 --no-perms" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="677" 41 | FILE2_PERM="777" 42 | FILE3_PERM="676" 43 | 44 | ### 45 | ### Create source files 46 | ### 47 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 48 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 49 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 50 | 51 | 52 | ### ################################################################################################ 53 | ### ################################################################################################ 54 | ### 55 | ### DEFINE CHECKS 56 | ### 57 | ### ################################################################################################ 58 | ### ################################################################################################ 59 | 60 | check() { 61 | local file="${1}" 62 | local perm="${2}" 63 | local destination 64 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 65 | 66 | print_subline "Validate ${file}" 67 | check_dst_file_perm "${file}" "${perm}" "$(get_default_dest_file_perm "${perm}")" "${destination}" 68 | } 69 | 70 | 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | ### 74 | ### Run backup (Round 1) 75 | ### 76 | ### ################################################################################################ 77 | ### ################################################################################################ 78 | 79 | print_headline "Backup (Round 1)" 80 | 81 | ### 82 | ### Backup 83 | ### 84 | print_subline "Run Backup" 85 | run_backup \ 86 | "${SCRIPTPATH}/../timemachine" \ 87 | "${SRC_DIR}" \ 88 | "${DST_DIR}" \ 89 | "${RSYNC_ARGS}" \ 90 | "full" 91 | 92 | ### 93 | ### Check 94 | ### 95 | check "${FILE1_NAME}" "${FILE1_PERM}" 96 | check "${FILE2_NAME}" "${FILE2_PERM}" 97 | check "${FILE3_NAME}" "${FILE3_PERM}" 98 | 99 | 100 | ### ################################################################################################ 101 | ### ################################################################################################ 102 | ### 103 | ### Run backup (Round 2) 104 | ### 105 | ### ################################################################################################ 106 | ### ################################################################################################ 107 | 108 | print_headline "Backup (Round 2)" 109 | 110 | ### 111 | ### Backup 112 | ### 113 | print_subline "Run Backup" 114 | run_backup \ 115 | "${SCRIPTPATH}/../timemachine" \ 116 | "${SRC_DIR}" \ 117 | "${DST_DIR}" \ 118 | "${RSYNC_ARGS}" \ 119 | "incremental" 120 | 121 | ### 122 | ### Check 123 | ### 124 | check "${FILE1_NAME}" "${FILE1_PERM}" 125 | check "${FILE2_NAME}" "${FILE2_PERM}" 126 | check "${FILE3_NAME}" "${FILE3_PERM}" 127 | -------------------------------------------------------------------------------- /tests/04-run-local-no_times.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="-- --no-times" 17 | 18 | print_section "04 --no-times" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="677" 41 | FILE2_PERM="777" 42 | FILE3_PERM="676" 43 | 44 | ### 45 | ### Create source files 46 | ### 47 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 48 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 49 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 50 | sleep 2 51 | 52 | 53 | ### ################################################################################################ 54 | ### ################################################################################################ 55 | ### 56 | ### DEFINE CHECKS 57 | ### 58 | ### ################################################################################################ 59 | ### ################################################################################################ 60 | 61 | check() { 62 | local file="${1}" 63 | local destination= 64 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 65 | 66 | print_subline "Validate ${file}" 67 | check_src_dst_file_mod_time "${file}" "${SRC_DIR}" "${destination}" "0" 68 | } 69 | 70 | 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | ### 74 | ### Run backup (Round 1) 75 | ### 76 | ### ################################################################################################ 77 | ### ################################################################################################ 78 | 79 | print_headline "Backup (Round 1)" 80 | 81 | ### 82 | ### Backup 83 | ### 84 | print_subline "Run Backup" 85 | run_backup \ 86 | "${SCRIPTPATH}/../timemachine" \ 87 | "${SRC_DIR}" \ 88 | "${DST_DIR}" \ 89 | "${RSYNC_ARGS}" \ 90 | "full" 91 | 92 | ### 93 | ### Check 94 | ### 95 | check "${FILE1_NAME}" 96 | check "${FILE2_NAME}" 97 | check "${FILE3_NAME}" 98 | 99 | 100 | ### ################################################################################################ 101 | ### ################################################################################################ 102 | ### 103 | ### Run backup (Round 2) 104 | ### 105 | ### ################################################################################################ 106 | ### ################################################################################################ 107 | 108 | print_headline "Backup (Round 2)" 109 | 110 | ### 111 | ### Backup 112 | ### 113 | print_subline "Run Backup" 114 | run_backup \ 115 | "${SCRIPTPATH}/../timemachine" \ 116 | "${SRC_DIR}" \ 117 | "${DST_DIR}" \ 118 | "${RSYNC_ARGS}" \ 119 | "incremental" 120 | 121 | ### 122 | ### Check 123 | ### 124 | check "${FILE1_NAME}" 125 | check "${FILE2_NAME}" 126 | check "${FILE3_NAME}" 127 | -------------------------------------------------------------------------------- /tests/05-run-local-copy_links.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="-- --copy-links" 17 | 18 | print_section "05 --copy-links" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file1.txt" 37 | FILE2_NAME="file2.txt" 38 | FILE3_NAME="sub/file3.txt" 39 | 40 | FILE1_PERM="607" 41 | FILE2_PERM="707" 42 | FILE3_PERM="607" 43 | 44 | LINK1_NAME="links/link1.txt" 45 | LINK2_NAME="links/link2.txt" 46 | LINK3_NAME="links/link3.txt" 47 | 48 | LINK1_FROM="../${FILE1_NAME}" 49 | LINK2_FROM="../${FILE2_NAME}" 50 | LINK3_FROM="../${FILE3_NAME}" 51 | 52 | 53 | ### 54 | ### Create source files 55 | ### 56 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 57 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 58 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 59 | 60 | create_link "${SRC_DIR}" "${LINK1_NAME}" "${LINK1_FROM}" 61 | create_link "${SRC_DIR}" "${LINK2_NAME}" "${LINK2_FROM}" 62 | create_link "${SRC_DIR}" "${LINK3_NAME}" "${LINK3_FROM}" 63 | 64 | 65 | ### ################################################################################################ 66 | ### ################################################################################################ 67 | ### 68 | ### DEFINE CHECKS 69 | ### 70 | ### ################################################################################################ 71 | ### ################################################################################################ 72 | 73 | check_file() { 74 | local file="${1}" 75 | local destination= 76 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 77 | 78 | print_subline "Validate ${file}" 79 | check_dst_file_is_file "${file}" "${destination}" 80 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 81 | } 82 | 83 | check_link() { 84 | local link="${1}" 85 | local destination= 86 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 87 | 88 | print_subline "Validate ${link}" 89 | check_dst_file_is_file "${link}" "${destination}" 90 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 91 | } 92 | 93 | 94 | ### ################################################################################################ 95 | ### ################################################################################################ 96 | ### 97 | ### Run backup (Round 1) 98 | ### 99 | ### ################################################################################################ 100 | ### ################################################################################################ 101 | 102 | print_headline "Backup (Round 1)" 103 | 104 | print_subline "Run Backup" 105 | run_backup \ 106 | "${SCRIPTPATH}/../timemachine" \ 107 | "${SRC_DIR}" \ 108 | "${DST_DIR}" \ 109 | "${RSYNC_ARGS}" \ 110 | "full" 111 | 112 | check_file "${FILE1_NAME}" 113 | check_file "${FILE2_NAME}" 114 | check_file "${FILE3_NAME}" 115 | 116 | check_link "${LINK1_NAME}" 117 | check_link "${LINK2_NAME}" 118 | check_link "${LINK3_NAME}" 119 | 120 | 121 | ### ################################################################################################ 122 | ### ################################################################################################ 123 | ### 124 | ### Run backup (Round 2) 125 | ### 126 | ### ################################################################################################ 127 | ### ################################################################################################ 128 | 129 | print_headline "Backup (Round 2)" 130 | 131 | print_subline "Run Backup" 132 | run_backup \ 133 | "${SCRIPTPATH}/../timemachine" \ 134 | "${SRC_DIR}" \ 135 | "${DST_DIR}" \ 136 | "${RSYNC_ARGS}" \ 137 | "incremental" 138 | 139 | check_file "${FILE1_NAME}" 140 | check_file "${FILE2_NAME}" 141 | check_file "${FILE3_NAME}" 142 | 143 | check_link "${LINK1_NAME}" 144 | check_link "${LINK2_NAME}" 145 | check_link "${LINK3_NAME}" 146 | -------------------------------------------------------------------------------- /tests/06-run-local-crazy-filename-chars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="-- --copy-links" 17 | 18 | print_section "06 crazy filename chars" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | SRC_DIR="$( create_tmp_dir )" 34 | DST_DIR="$( create_tmp_dir )" 35 | 36 | FILE1_NAME="file 1.txt" 37 | FILE2_NAME="file'2.txt" 38 | FILE3_NAME="file\"3.txt" 39 | FILE4_NAME="file\\4.txt" 40 | FILE5_NAME="sub sub/file5\\\".txt" 41 | FILE6_NAME="sub 'sub/file6\\'.txt" 42 | FILE7_NAME="sub \"sub/file7.txt" 43 | FILE8_NAME="sub \\sub/file*" 44 | 45 | FILE1_PERM="607" 46 | FILE2_PERM="707" 47 | FILE3_PERM="607" 48 | FILE4_PERM="607" 49 | FILE5_PERM="607" 50 | FILE6_PERM="607" 51 | FILE7_PERM="607" 52 | FILE8_PERM="607" 53 | 54 | ### 55 | ### Create source files 56 | ### 57 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 58 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 59 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 60 | create_file "${SRC_DIR}" "${FILE4_NAME}" "1" "${FILE4_PERM}" 61 | create_file "${SRC_DIR}" "${FILE5_NAME}" "1" "${FILE5_PERM}" 62 | create_file "${SRC_DIR}" "${FILE6_NAME}" "1" "${FILE6_PERM}" 63 | create_file "${SRC_DIR}" "${FILE7_NAME}" "1" "${FILE7_PERM}" 64 | create_file "${SRC_DIR}" "${FILE8_NAME}" "1" "${FILE8_PERM}" 65 | 66 | 67 | 68 | ### ################################################################################################ 69 | ### ################################################################################################ 70 | ### 71 | ### DEFINE CHECKS 72 | ### 73 | ### ################################################################################################ 74 | ### ################################################################################################ 75 | 76 | check_file() { 77 | local file="${1}" 78 | local destination= 79 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 80 | 81 | print_subline "Validate ${file}" 82 | check_dst_file_is_file "${file}" "${destination}" 83 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 84 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 85 | } 86 | 87 | check_link() { 88 | local link="${1}" 89 | local destination= 90 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 91 | 92 | print_subline "Validate ${link}" 93 | check_dst_file_is_file "${link}" "${destination}" 94 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 95 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 96 | } 97 | 98 | 99 | ### ################################################################################################ 100 | ### ################################################################################################ 101 | ### 102 | ### Run backup (Round 1) 103 | ### 104 | ### ################################################################################################ 105 | ### ################################################################################################ 106 | 107 | print_headline "Backup (Round 1)" 108 | 109 | print_subline "Run Backup" 110 | run_backup \ 111 | "${SCRIPTPATH}/../timemachine" \ 112 | "${SRC_DIR}" \ 113 | "${DST_DIR}" \ 114 | "${RSYNC_ARGS}" \ 115 | "full" 116 | 117 | check_file "${FILE1_NAME}" 118 | check_file "${FILE2_NAME}" 119 | check_file "${FILE3_NAME}" 120 | check_file "${FILE4_NAME}" 121 | check_file "${FILE5_NAME}" 122 | check_file "${FILE6_NAME}" 123 | check_file "${FILE7_NAME}" 124 | check_file "${FILE8_NAME}" 125 | 126 | 127 | ### ################################################################################################ 128 | ### ################################################################################################ 129 | ### 130 | ### Run backup (Round 2) 131 | ### 132 | ### ################################################################################################ 133 | ### ################################################################################################ 134 | 135 | print_headline "Backup (Round 2)" 136 | 137 | print_subline "Run Backup" 138 | run_backup \ 139 | "${SCRIPTPATH}/../timemachine" \ 140 | "${SRC_DIR}" \ 141 | "${DST_DIR}" \ 142 | "${RSYNC_ARGS}" \ 143 | "incremental" 144 | 145 | check_file "${FILE1_NAME}" 146 | check_file "${FILE2_NAME}" 147 | check_file "${FILE3_NAME}" 148 | check_file "${FILE4_NAME}" 149 | check_file "${FILE5_NAME}" 150 | check_file "${FILE6_NAME}" 151 | check_file "${FILE7_NAME}" 152 | check_file "${FILE8_NAME}" 153 | -------------------------------------------------------------------------------- /tests/06-run-local-crazy-pathname-chars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### RSYNC ARGUMENTS 15 | ### 16 | RSYNC_ARGS="-- --copy-links" 17 | 18 | print_section "06 crazy pathname chars" 19 | 20 | ### ################################################################################################ 21 | ### ################################################################################################ 22 | ### 23 | ### CREATE FILES AND DIRS 24 | ### 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | 28 | print_headline "Creating files and directories" 29 | 30 | ### 31 | ### Create source and target dir 32 | ### 33 | echo "# Create SRC_DIR" 34 | SRC_DIR="$( create_tmp_dir "1" "" " \"\\ \` \\# \$统一码-src'" )" 35 | echo "# Create DST_DIR" 36 | DST_DIR="$( create_tmp_dir "1" "" " '\\\" \` \\# \$统一码-dst" )" 37 | 38 | FILE1_NAME="file 1.txt" 39 | FILE2_NAME="file'2.txt" 40 | FILE3_NAME="file\"3.txt" 41 | FILE4_NAME="file\\4.txt" 42 | FILE5_NAME="sub sub/file5\\\".txt" 43 | FILE6_NAME="sub 'sub/file6\\'.txt" 44 | FILE7_NAME="sub \"sub/file7.txt" 45 | FILE8_NAME="sub \\sub/file*" 46 | 47 | FILE1_PERM="607" 48 | FILE2_PERM="707" 49 | FILE3_PERM="607" 50 | FILE4_PERM="607" 51 | FILE5_PERM="607" 52 | FILE6_PERM="607" 53 | FILE7_PERM="607" 54 | FILE8_PERM="607" 55 | 56 | ### 57 | ### Create source files 58 | ### 59 | printf "# Create FILE1: %s/%s\\n" "${SRC_DIR}" "${FILE1_NAME}" 60 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 61 | 62 | printf "# Create FILE2: %s/%s\\n" "${SRC_DIR}" "${FILE2_NAME}" 63 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 64 | 65 | printf "# Create FILE3: %s/%s\\n" "${SRC_DIR}" "${FILE3_NAME}" 66 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 67 | 68 | printf "# Create FILE4: %s/%s\\n" "${SRC_DIR}" "${FILE4_NAME}" 69 | create_file "${SRC_DIR}" "${FILE4_NAME}" "1" "${FILE4_PERM}" 70 | 71 | printf "# Create FILE5: %s/%s\\n" "${SRC_DIR}" "${FILE5_NAME}" 72 | create_file "${SRC_DIR}" "${FILE5_NAME}" "1" "${FILE5_PERM}" 73 | 74 | printf "# Create FILE6: %s/%s\\n" "${SRC_DIR}" "${FILE6_NAME}" 75 | create_file "${SRC_DIR}" "${FILE6_NAME}" "1" "${FILE6_PERM}" 76 | 77 | printf "# Create FILE7: %s/%s\\n" "${SRC_DIR}" "${FILE7_NAME}" 78 | create_file "${SRC_DIR}" "${FILE7_NAME}" "1" "${FILE7_PERM}" 79 | 80 | printf "# Create FILE8: %s/%s\\n" "${SRC_DIR}" "${FILE8_NAME}" 81 | create_file "${SRC_DIR}" "${FILE8_NAME}" "1" "${FILE8_PERM}" 82 | 83 | 84 | 85 | ### ################################################################################################ 86 | ### ################################################################################################ 87 | ### 88 | ### DEFINE CHECKS 89 | ### 90 | ### ################################################################################################ 91 | ### ################################################################################################ 92 | 93 | check_file() { 94 | local file="${1}" 95 | local destination= 96 | #destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 97 | destination="${DST_DIR}/current/$(printf "%q" "$(eval "basename ${SRC_DIR}")")" 98 | 99 | print_subline "Validate ${file}" 100 | check_dst_file_is_file "${file}" "${destination}" 101 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 102 | check_src_dst_file_equal "${file}" "${SRC_DIR}" "${destination}" 103 | } 104 | 105 | check_link() { 106 | local link="${1}" 107 | local destination= 108 | destination="${DST_DIR}/current/$(basename "${SRC_DIR}")" 109 | 110 | print_subline "Validate ${link}" 111 | check_dst_file_is_file "${link}" "${destination}" 112 | check_src_dst_file_exist "${file}" "${SRC_DIR}" "${destination}" 113 | check_src_dst_file_equal "${link}" "${SRC_DIR}" "${destination}" 114 | } 115 | 116 | 117 | ### ################################################################################################ 118 | ### ################################################################################################ 119 | ### 120 | ### Run backup (Round 1) 121 | ### 122 | ### ################################################################################################ 123 | ### ################################################################################################ 124 | 125 | print_headline "Backup (Round 1)" 126 | 127 | print_subline "Run Backup" 128 | run_backup \ 129 | "${SCRIPTPATH}/../timemachine" \ 130 | "${SRC_DIR}" \ 131 | "${DST_DIR}" \ 132 | "${RSYNC_ARGS}" \ 133 | "full" 134 | 135 | check_file "${FILE1_NAME}" 136 | check_file "${FILE2_NAME}" 137 | check_file "${FILE3_NAME}" 138 | check_file "${FILE4_NAME}" 139 | check_file "${FILE5_NAME}" 140 | check_file "${FILE6_NAME}" 141 | check_file "${FILE7_NAME}" 142 | check_file "${FILE8_NAME}" 143 | 144 | 145 | ### ################################################################################################ 146 | ### ################################################################################################ 147 | ### 148 | ### Run backup (Round 2) 149 | ### 150 | ### ################################################################################################ 151 | ### ################################################################################################ 152 | 153 | print_headline "Backup (Round 2)" 154 | 155 | print_subline "Run Backup" 156 | run_backup \ 157 | "${SCRIPTPATH}/../timemachine" \ 158 | "${SRC_DIR}" \ 159 | "${DST_DIR}" \ 160 | "${RSYNC_ARGS}" \ 161 | "incremental" 162 | 163 | check_file "${FILE1_NAME}" 164 | check_file "${FILE2_NAME}" 165 | check_file "${FILE3_NAME}" 166 | check_file "${FILE4_NAME}" 167 | check_file "${FILE5_NAME}" 168 | check_file "${FILE6_NAME}" 169 | check_file "${FILE7_NAME}" 170 | check_file "${FILE8_NAME}" 171 | -------------------------------------------------------------------------------- /tests/10-run-remote-default-abs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="" 21 | RSYNC_ARGS= 22 | 23 | print_section "10 Remote (absolute path)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_USER}@${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_USER}@${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/10-run-remote-default-rel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="" 21 | RSYNC_ARGS= 22 | 23 | print_section "10 Remote (relative path)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_USER}@${SSH_HOST}" \ 111 | "backup1" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" \ 114 | "/root/" 115 | 116 | check "${FILE1_NAME}" "${FILE1_PERM}" 117 | check "${FILE2_NAME}" "${FILE2_PERM}" 118 | check "${FILE3_NAME}" "${FILE3_PERM}" 119 | 120 | 121 | ### ################################################################################################ 122 | ### ################################################################################################ 123 | ### 124 | ### Run backup (Round 2) 125 | ### 126 | ### ################################################################################################ 127 | ### ################################################################################################ 128 | 129 | print_headline "Backup (Round 2)" 130 | 131 | print_subline "Run Backup" 132 | run_remote_backup \ 133 | "ssh-client" \ 134 | "ssh-server" \ 135 | "/usr/bin/timemachine" \ 136 | "${TIMEMACHINE_ARGS}" \ 137 | "/data" \ 138 | "${SSH_USER}@${SSH_HOST}" \ 139 | "backup1" \ 140 | "${RSYNC_ARGS}" \ 141 | "incremental" \ 142 | "/root/" 143 | 144 | check "${FILE1_NAME}" "${FILE1_PERM}" 145 | check "${FILE2_NAME}" "${FILE2_PERM}" 146 | check "${FILE3_NAME}" "${FILE3_PERM}" 147 | 148 | 149 | ### ################################################################################################ 150 | ### ################################################################################################ 151 | ### 152 | ### Cleanup 153 | ### 154 | ### ################################################################################################ 155 | ### ################################################################################################ 156 | 157 | print_headline "Cleanup" 158 | 159 | ### 160 | ### Remove artifacts 161 | ### 162 | run "docker rm -f ssh-server" 163 | run "docker rm -f ssh-client" 164 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_1111-nouser.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | #SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="1111" 19 | 20 | TIMEMACHINE_ARGS="--port ${SSH_PORT}" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (no user && non-standard SSH port: 1111)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_1111-user.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="1111" 19 | 20 | TIMEMACHINE_ARGS="--port ${SSH_PORT}" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (explicit user && non-standard SSH port: 1111)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_USER}@${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_USER}@${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_22-nouser.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | #SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="--port ${SSH_PORT}" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (no user && non-standard SSH port: 22)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_22-user.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="--port ${SSH_PORT}" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (explicit user && non-standard SSH port: 22)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_USER}@${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_USER}@${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_def-nouser.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | #SSH_USER="root" 17 | SSH_HOST="server" 18 | #SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (no user && default SSH port)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/11-run-remote-ssh_port_def-user.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | #SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="" 21 | RSYNC_ARGS= 22 | 23 | print_section "11 Remote (explicit user && default SSH port)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | 40 | FILE1_NAME="file1.txt" 41 | FILE2_NAME="file2.txt" 42 | FILE3_NAME="sub/file3.txt" 43 | 44 | FILE1_PERM="607" 45 | FILE2_PERM="707" 46 | FILE3_PERM="607" 47 | 48 | ### 49 | ### Create source files 50 | ### 51 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 52 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 53 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 54 | 55 | 56 | ### ################################################################################################ 57 | ### ################################################################################################ 58 | ### 59 | ### DEFINE CHECKS 60 | ### 61 | ### ################################################################################################ 62 | ### ################################################################################################ 63 | 64 | check() { 65 | printf "" 66 | } 67 | 68 | 69 | ### ################################################################################################ 70 | ### ################################################################################################ 71 | ### 72 | ### Start container 73 | ### 74 | ### ################################################################################################ 75 | ### ################################################################################################ 76 | 77 | print_headline "Start container" 78 | 79 | ### 80 | ### Kill accidentally left artifacts 81 | ### 82 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 83 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 84 | 85 | ### 86 | ### Startup 87 | ### 88 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -D" 89 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' cytopia/ssh-client" 90 | run "sleep 5" 91 | 92 | 93 | ### ################################################################################################ 94 | ### ################################################################################################ 95 | ### 96 | ### Run backup (Round 1) 97 | ### 98 | ### ################################################################################################ 99 | ### ################################################################################################ 100 | 101 | print_headline "Backup (Round 1)" 102 | 103 | print_subline "Run Backup" 104 | run_remote_backup \ 105 | "ssh-client" \ 106 | "ssh-server" \ 107 | "/usr/bin/timemachine" \ 108 | "${TIMEMACHINE_ARGS}" \ 109 | "/data" \ 110 | "${SSH_USER}@${SSH_HOST}" \ 111 | "/backup2" \ 112 | "${RSYNC_ARGS}" \ 113 | "full" 114 | 115 | check "${FILE1_NAME}" "${FILE1_PERM}" 116 | check "${FILE2_NAME}" "${FILE2_PERM}" 117 | check "${FILE3_NAME}" "${FILE3_PERM}" 118 | 119 | 120 | ### ################################################################################################ 121 | ### ################################################################################################ 122 | ### 123 | ### Run backup (Round 2) 124 | ### 125 | ### ################################################################################################ 126 | ### ################################################################################################ 127 | 128 | print_headline "Backup (Round 2)" 129 | 130 | print_subline "Run Backup" 131 | run_remote_backup \ 132 | "ssh-client" \ 133 | "ssh-server" \ 134 | "/usr/bin/timemachine" \ 135 | "${TIMEMACHINE_ARGS}" \ 136 | "/data" \ 137 | "${SSH_USER}@${SSH_HOST}" \ 138 | "/backup2" \ 139 | "${RSYNC_ARGS}" \ 140 | "incremental" 141 | 142 | check "${FILE1_NAME}" "${FILE1_PERM}" 143 | check "${FILE2_NAME}" "${FILE2_PERM}" 144 | check "${FILE3_NAME}" "${FILE3_PERM}" 145 | 146 | 147 | ### ################################################################################################ 148 | ### ################################################################################################ 149 | ### 150 | ### Cleanup 151 | ### 152 | ### ################################################################################################ 153 | ### ################################################################################################ 154 | 155 | print_headline "Cleanup" 156 | 157 | ### 158 | ### Remove artifacts 159 | ### 160 | run "docker rm -f ssh-server" 161 | run "docker rm -f ssh-client" 162 | -------------------------------------------------------------------------------- /tests/12-run-remote-ssh_config-default.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="22" 19 | SSH_ALIAS="mysshalias" 20 | 21 | TIMEMACHINE_ARGS="" 22 | RSYNC_ARGS= 23 | 24 | print_section "12 Remote (SSH config with standard SSH port: 22)" 25 | 26 | ### ################################################################################################ 27 | ### ################################################################################################ 28 | ### 29 | ### CREATE FILES AND DIRS 30 | ### 31 | ### ################################################################################################ 32 | ### ################################################################################################ 33 | 34 | print_headline "Creating files and directories" 35 | 36 | ### 37 | ### Create source dir 38 | ### 39 | SRC_DIR="$( create_tmp_dir )" 40 | 41 | FILE1_NAME="file1.txt" 42 | FILE2_NAME="file2.txt" 43 | FILE3_NAME="sub/file3.txt" 44 | 45 | FILE1_PERM="607" 46 | FILE2_PERM="707" 47 | FILE3_PERM="607" 48 | 49 | ### 50 | ### Create source files 51 | ### 52 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 53 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 54 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 55 | 56 | 57 | ### ################################################################################################ 58 | ### ################################################################################################ 59 | ### 60 | ### DEFINE CHECKS 61 | ### 62 | ### ################################################################################################ 63 | ### ################################################################################################ 64 | 65 | check() { 66 | printf "" 67 | } 68 | 69 | 70 | ### ################################################################################################ 71 | ### ################################################################################################ 72 | ### 73 | ### Start container 74 | ### 75 | ### ################################################################################################ 76 | ### ################################################################################################ 77 | 78 | print_headline "Start container" 79 | 80 | ### 81 | ### Kill accidentally left artifacts 82 | ### 83 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 84 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 85 | 86 | ### 87 | ### Create SSH client config 88 | ### 89 | SSH_CONFIG="$( create_tmp_file )" 90 | { 91 | echo "Host ${SSH_ALIAS}"; 92 | echo " HostName ${SSH_HOST}"; 93 | echo " Port ${SSH_PORT}"; 94 | echo " User ${SSH_USER}"; 95 | } > "${SSH_CONFIG}" 96 | 97 | 98 | ### 99 | ### Startup 100 | ### 101 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 102 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' -v '${SSH_CONFIG}:/root/.ssh/config' cytopia/ssh-client" 103 | run "sleep 5" 104 | 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_remote_backup \ 119 | "ssh-client" \ 120 | "ssh-server" \ 121 | "/usr/bin/timemachine" \ 122 | "${TIMEMACHINE_ARGS}" \ 123 | "/data" \ 124 | "${SSH_ALIAS}" \ 125 | "/backup2" \ 126 | "${RSYNC_ARGS}" \ 127 | "full" 128 | 129 | check "${FILE1_NAME}" "${FILE1_PERM}" 130 | check "${FILE2_NAME}" "${FILE2_PERM}" 131 | check "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | 134 | ### ################################################################################################ 135 | ### ################################################################################################ 136 | ### 137 | ### Run backup (Round 2) 138 | ### 139 | ### ################################################################################################ 140 | ### ################################################################################################ 141 | 142 | print_headline "Backup (Round 2)" 143 | 144 | print_subline "Run Backup" 145 | run_remote_backup \ 146 | "ssh-client" \ 147 | "ssh-server" \ 148 | "/usr/bin/timemachine" \ 149 | "${TIMEMACHINE_ARGS}" \ 150 | "/data" \ 151 | "${SSH_ALIAS}" \ 152 | "/backup2" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" 155 | 156 | check "${FILE1_NAME}" "${FILE1_PERM}" 157 | check "${FILE2_NAME}" "${FILE2_PERM}" 158 | check "${FILE3_NAME}" "${FILE3_PERM}" 159 | 160 | 161 | ### ################################################################################################ 162 | ### ################################################################################################ 163 | ### 164 | ### Cleanup 165 | ### 166 | ### ################################################################################################ 167 | ### ################################################################################################ 168 | 169 | print_headline "Cleanup" 170 | 171 | ### 172 | ### Remove artifacts 173 | ### 174 | run "docker rm -f ssh-server" 175 | run "docker rm -f ssh-client" 176 | -------------------------------------------------------------------------------- /tests/12-run-remote-ssh_config-port_1111.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="1111" 19 | SSH_ALIAS="mysshalias" 20 | 21 | TIMEMACHINE_ARGS="" 22 | RSYNC_ARGS= 23 | 24 | print_section "12 Remote (SSH config with non-standard SSH port: 1111)" 25 | 26 | ### ################################################################################################ 27 | ### ################################################################################################ 28 | ### 29 | ### CREATE FILES AND DIRS 30 | ### 31 | ### ################################################################################################ 32 | ### ################################################################################################ 33 | 34 | print_headline "Creating files and directories" 35 | 36 | ### 37 | ### Create source dir 38 | ### 39 | SRC_DIR="$( create_tmp_dir )" 40 | 41 | FILE1_NAME="file1.txt" 42 | FILE2_NAME="file2.txt" 43 | FILE3_NAME="sub/file3.txt" 44 | 45 | FILE1_PERM="607" 46 | FILE2_PERM="707" 47 | FILE3_PERM="607" 48 | 49 | ### 50 | ### Create source files 51 | ### 52 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 53 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 54 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 55 | 56 | 57 | ### ################################################################################################ 58 | ### ################################################################################################ 59 | ### 60 | ### DEFINE CHECKS 61 | ### 62 | ### ################################################################################################ 63 | ### ################################################################################################ 64 | 65 | check() { 66 | printf "" 67 | } 68 | 69 | 70 | ### ################################################################################################ 71 | ### ################################################################################################ 72 | ### 73 | ### Start container 74 | ### 75 | ### ################################################################################################ 76 | ### ################################################################################################ 77 | 78 | print_headline "Start container" 79 | 80 | ### 81 | ### Kill accidentally left artifacts 82 | ### 83 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 84 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 85 | 86 | ### 87 | ### Create SSH client config 88 | ### 89 | SSH_CONFIG="$( create_tmp_file )" 90 | { 91 | echo "Host ${SSH_ALIAS}"; 92 | echo " HostName ${SSH_HOST}"; 93 | echo " Port ${SSH_PORT}"; 94 | echo " User ${SSH_USER}"; 95 | } > "${SSH_CONFIG}" 96 | 97 | 98 | ### 99 | ### Startup 100 | ### 101 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 102 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' -v '${SSH_CONFIG}:/root/.ssh/config' cytopia/ssh-client" 103 | run "sleep 5" 104 | 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_remote_backup \ 119 | "ssh-client" \ 120 | "ssh-server" \ 121 | "/usr/bin/timemachine" \ 122 | "${TIMEMACHINE_ARGS}" \ 123 | "/data" \ 124 | "${SSH_ALIAS}" \ 125 | "/backup2" \ 126 | "${RSYNC_ARGS}" \ 127 | "full" 128 | 129 | check "${FILE1_NAME}" "${FILE1_PERM}" 130 | check "${FILE2_NAME}" "${FILE2_PERM}" 131 | check "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | 134 | ### ################################################################################################ 135 | ### ################################################################################################ 136 | ### 137 | ### Run backup (Round 2) 138 | ### 139 | ### ################################################################################################ 140 | ### ################################################################################################ 141 | 142 | print_headline "Backup (Round 2)" 143 | 144 | print_subline "Run Backup" 145 | run_remote_backup \ 146 | "ssh-client" \ 147 | "ssh-server" \ 148 | "/usr/bin/timemachine" \ 149 | "${TIMEMACHINE_ARGS}" \ 150 | "/data" \ 151 | "${SSH_ALIAS}" \ 152 | "/backup2" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" 155 | 156 | check "${FILE1_NAME}" "${FILE1_PERM}" 157 | check "${FILE2_NAME}" "${FILE2_PERM}" 158 | check "${FILE3_NAME}" "${FILE3_PERM}" 159 | 160 | 161 | ### ################################################################################################ 162 | ### ################################################################################################ 163 | ### 164 | ### Cleanup 165 | ### 166 | ### ################################################################################################ 167 | ### ################################################################################################ 168 | 169 | print_headline "Cleanup" 170 | 171 | ### 172 | ### Remove artifacts 173 | ### 174 | run "docker rm -f ssh-server" 175 | run "docker rm -f ssh-client" 176 | -------------------------------------------------------------------------------- /tests/12-run-remote-ssh_config-port_overwrite.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | SSH_USER="root" 17 | SSH_HOST="server" 18 | SSH_PORT="1111" 19 | SSH_ALIAS="mysshalias" 20 | 21 | TIMEMACHINE_ARGS="--port ${SSH_PORT}" 22 | RSYNC_ARGS= 23 | 24 | print_section "12 Remote (SSH config and overwrite port)" 25 | 26 | ### ################################################################################################ 27 | ### ################################################################################################ 28 | ### 29 | ### CREATE FILES AND DIRS 30 | ### 31 | ### ################################################################################################ 32 | ### ################################################################################################ 33 | 34 | print_headline "Creating files and directories" 35 | 36 | ### 37 | ### Create source dir 38 | ### 39 | SRC_DIR="$( create_tmp_dir )" 40 | 41 | FILE1_NAME="file1.txt" 42 | FILE2_NAME="file2.txt" 43 | FILE3_NAME="sub/file3.txt" 44 | 45 | FILE1_PERM="607" 46 | FILE2_PERM="707" 47 | FILE3_PERM="607" 48 | 49 | ### 50 | ### Create source files 51 | ### 52 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 53 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 54 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 55 | 56 | 57 | ### ################################################################################################ 58 | ### ################################################################################################ 59 | ### 60 | ### DEFINE CHECKS 61 | ### 62 | ### ################################################################################################ 63 | ### ################################################################################################ 64 | 65 | check() { 66 | printf "" 67 | } 68 | 69 | 70 | ### ################################################################################################ 71 | ### ################################################################################################ 72 | ### 73 | ### Start container 74 | ### 75 | ### ################################################################################################ 76 | ### ################################################################################################ 77 | 78 | print_headline "Start container" 79 | 80 | ### 81 | ### Kill accidentally left artifacts 82 | ### 83 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 84 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 85 | 86 | ### 87 | ### Create SSH client config 88 | ### 89 | SSH_CONFIG="$( create_tmp_file )" 90 | { 91 | echo "Host ${SSH_ALIAS}"; 92 | echo " HostName ${SSH_HOST}"; 93 | echo " Port 50"; # This will be overwritten by the run 94 | echo " User ${SSH_USER}"; 95 | } > "${SSH_CONFIG}" 96 | 97 | 98 | ### 99 | ### Startup 100 | ### 101 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -p ${SSH_PORT} -D" 102 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v '${SRC_DIR}:/data' -v '${SSH_CONFIG}:/root/.ssh/config' cytopia/ssh-client" 103 | run "sleep 5" 104 | 105 | 106 | 107 | ### ################################################################################################ 108 | ### ################################################################################################ 109 | ### 110 | ### Run backup (Round 1) 111 | ### 112 | ### ################################################################################################ 113 | ### ################################################################################################ 114 | 115 | print_headline "Backup (Round 1)" 116 | 117 | print_subline "Run Backup" 118 | run_remote_backup \ 119 | "ssh-client" \ 120 | "ssh-server" \ 121 | "/usr/bin/timemachine" \ 122 | "${TIMEMACHINE_ARGS}" \ 123 | "/data" \ 124 | "${SSH_ALIAS}" \ 125 | "/backup2" \ 126 | "${RSYNC_ARGS}" \ 127 | "full" 128 | 129 | check "${FILE1_NAME}" "${FILE1_PERM}" 130 | check "${FILE2_NAME}" "${FILE2_PERM}" 131 | check "${FILE3_NAME}" "${FILE3_PERM}" 132 | 133 | 134 | ### ################################################################################################ 135 | ### ################################################################################################ 136 | ### 137 | ### Run backup (Round 2) 138 | ### 139 | ### ################################################################################################ 140 | ### ################################################################################################ 141 | 142 | print_headline "Backup (Round 2)" 143 | 144 | print_subline "Run Backup" 145 | run_remote_backup \ 146 | "ssh-client" \ 147 | "ssh-server" \ 148 | "/usr/bin/timemachine" \ 149 | "${TIMEMACHINE_ARGS}" \ 150 | "/data" \ 151 | "${SSH_ALIAS}" \ 152 | "/backup2" \ 153 | "${RSYNC_ARGS}" \ 154 | "incremental" 155 | 156 | check "${FILE1_NAME}" "${FILE1_PERM}" 157 | check "${FILE2_NAME}" "${FILE2_PERM}" 158 | check "${FILE3_NAME}" "${FILE3_PERM}" 159 | 160 | 161 | ### ################################################################################################ 162 | ### ################################################################################################ 163 | ### 164 | ### Cleanup 165 | ### 166 | ### ################################################################################################ 167 | ### ################################################################################################ 168 | 169 | print_headline "Cleanup" 170 | 171 | ### 172 | ### Remove artifacts 173 | ### 174 | run "docker rm -f ssh-server" 175 | run "docker rm -f ssh-client" 176 | -------------------------------------------------------------------------------- /tests/13-run-remote-crazy-source-pathname-chars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | set -u 5 | set -o pipefail 6 | 7 | SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" 8 | FUNCPATH="${SCRIPTPATH}/.lib/functions.sh" 9 | # shellcheck disable=SC1090 10 | . "${FUNCPATH}" 11 | 12 | 13 | ### 14 | ### GLOBALS 15 | ### 16 | #SSH_USER="root" 17 | SSH_HOST="server" 18 | #SSH_PORT="22" 19 | 20 | TIMEMACHINE_ARGS="" 21 | RSYNC_ARGS="--progress" 22 | 23 | print_section "12 Remote (crazy pathname chars)" 24 | 25 | ### ################################################################################################ 26 | ### ################################################################################################ 27 | ### 28 | ### CREATE FILES AND DIRS 29 | ### 30 | ### ################################################################################################ 31 | ### ################################################################################################ 32 | 33 | print_headline "Creating files and directories" 34 | 35 | ### 36 | ### Create source dir 37 | ### 38 | SRC_DIR="$( create_tmp_dir )" 39 | DOCKER_SRC_DIR="/$(printf "%s" ' "\ ` $统一码-$-src')" 40 | DOCKER_DST_DIR="/backup-dst" 41 | 42 | FILE1_NAME="file1.txt" 43 | FILE2_NAME="file2.txt" 44 | FILE3_NAME="sub/file3.txt" 45 | 46 | FILE1_PERM="607" 47 | FILE2_PERM="707" 48 | FILE3_PERM="607" 49 | 50 | ### 51 | ### Create source files 52 | ### 53 | create_file "${SRC_DIR}" "${FILE1_NAME}" "2" "${FILE1_PERM}" 54 | create_file "${SRC_DIR}" "${FILE2_NAME}" "5" "${FILE2_PERM}" 55 | create_file "${SRC_DIR}" "${FILE3_NAME}" "1" "${FILE3_PERM}" 56 | 57 | 58 | ### ################################################################################################ 59 | ### ################################################################################################ 60 | ### 61 | ### DEFINE CHECKS 62 | ### 63 | ### ################################################################################################ 64 | ### ################################################################################################ 65 | 66 | check() { 67 | printf "" 68 | } 69 | 70 | 71 | ### ################################################################################################ 72 | ### ################################################################################################ 73 | ### 74 | ### Start container 75 | ### 76 | ### ################################################################################################ 77 | ### ################################################################################################ 78 | 79 | print_headline "Start container" 80 | 81 | ### 82 | ### Kill accidentally left artifacts 83 | ### 84 | run "docker rm -f ssh-server || true" >/dev/null 2>&1 85 | run "docker rm -f ssh-client || true" >/dev/null 2>&1 86 | 87 | ### 88 | ### Startup 89 | ### 90 | run "docker run -d --rm --name ssh-server -h server cytopia/ssh-server /usr/sbin/sshd -D" 91 | run "docker exec ssh-server mkdir $(printf "%q" "${DOCKER_DST_DIR}")" 92 | run "docker run -d --rm --name ssh-client -h client --link ssh-server -v '${SCRIPTPATH}/../timemachine:/usr/bin/timemachine' -v ${SRC_DIR}:/$(printf "%q" "${DOCKER_SRC_DIR}") cytopia/ssh-client" 93 | run "sleep 5" 94 | 95 | 96 | ### ################################################################################################ 97 | ### ################################################################################################ 98 | ### 99 | ### Run backup (Round 1) 100 | ### 101 | ### ################################################################################################ 102 | ### ################################################################################################ 103 | 104 | print_headline "Backup (Round 1)" 105 | 106 | print_subline "Run Backup" 107 | run_remote_backup \ 108 | "ssh-client" \ 109 | "ssh-server" \ 110 | "/usr/bin/timemachine" \ 111 | "${TIMEMACHINE_ARGS}" \ 112 | "${DOCKER_SRC_DIR}" \ 113 | "${SSH_HOST}" \ 114 | "${DOCKER_DST_DIR}" \ 115 | "${RSYNC_ARGS}" \ 116 | "full" 117 | 118 | check "${FILE1_NAME}" "${FILE1_PERM}" 119 | check "${FILE2_NAME}" "${FILE2_PERM}" 120 | check "${FILE3_NAME}" "${FILE3_PERM}" 121 | 122 | 123 | ### ################################################################################################ 124 | ### ################################################################################################ 125 | ### 126 | ### Run backup (Round 2) 127 | ### 128 | ### ################################################################################################ 129 | ### ################################################################################################ 130 | 131 | print_headline "Backup (Round 2)" 132 | 133 | print_subline "Run Backup" 134 | run_remote_backup \ 135 | "ssh-client" \ 136 | "ssh-server" \ 137 | "/usr/bin/timemachine" \ 138 | "${TIMEMACHINE_ARGS}" \ 139 | "${DOCKER_SRC_DIR}" \ 140 | "${SSH_HOST}" \ 141 | "${DOCKER_DST_DIR}" \ 142 | "${RSYNC_ARGS}" \ 143 | "incremental" 144 | 145 | check "${FILE1_NAME}" "${FILE1_PERM}" 146 | check "${FILE2_NAME}" "${FILE2_PERM}" 147 | check "${FILE3_NAME}" "${FILE3_PERM}" 148 | 149 | 150 | ### ################################################################################################ 151 | ### ################################################################################################ 152 | ### 153 | ### Cleanup 154 | ### 155 | ### ################################################################################################ 156 | ### ################################################################################################ 157 | 158 | print_headline "Cleanup" 159 | 160 | ### 161 | ### Remove artifacts 162 | ### 163 | run "docker rm -f ssh-server" 164 | run "docker rm -f ssh-client" 165 | -------------------------------------------------------------------------------- /tests/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | version: '2.3' 4 | services: 5 | 6 | server: 7 | hostname: server 8 | build: ./docker-ssh-server 9 | image: cytopia/ssh-server 10 | ports: 11 | - "2222:22" 12 | 13 | client: 14 | hostname: client 15 | build: ./docker-ssh-client 16 | image: cytopia/ssh-client 17 | volumes: 18 | - "../timemachine:/usr/bin/timemachine" 19 | - "../tests:/tests" 20 | depends_on: 21 | - server 22 | -------------------------------------------------------------------------------- /tests/docker-ssh-client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster-slim 2 | 3 | 4 | ### 5 | ### Install SSH Server 6 | ### 7 | RUN set -eux \ 8 | && apt update \ 9 | && apt install -y \ 10 | rsync \ 11 | openssh-client 12 | 13 | ### 14 | ### Configure SSH 15 | ### 16 | RUN set -eux \ 17 | && mkdir -p /root/.ssh \ 18 | && chmod 0700 /root/.ssh 19 | 20 | ### 21 | ### Add private key 22 | ### 23 | COPY id_rsa /root/.ssh/id_rsa 24 | 25 | RUN set -eux \ 26 | && chmod 0400 /root/.ssh/id_rsa 27 | 28 | ### 29 | ### Add backup directories 30 | ### 31 | RUN set -eux \ 32 | && mkdir -p /root/backup1 \ 33 | && mkdir -p /backup2 34 | 35 | COPY docker-entrypoint.sh /docker-entrypoint.sh 36 | CMD ["/docker-entrypoint.sh"] 37 | -------------------------------------------------------------------------------- /tests/docker-ssh-client/README.md: -------------------------------------------------------------------------------- 1 | # Docker SSH client 2 | 3 | ## Note 4 | 5 | The bundled ssh private key is soley for the purpose of this Docker image and has not accidentally 6 | been leaked :-) 7 | -------------------------------------------------------------------------------- /tests/docker-ssh-client/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | chown -R root:root /root 4 | exec sleep 99999 5 | -------------------------------------------------------------------------------- /tests/docker-ssh-client/id_rsa: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIJKgIBAAKCAgEAgpLCyAx2grqKHSsdMw5yKCfOeKu1jsOKHsabVGma05yJH/E9 3 | GmFWGvhFWtF7Kufirb5s4aMOFYnsXj6FCcaim/5ru20P2WwnUS70HQ8LQfANSutr 4 | FSXb1LJoNw3qsz/7yWLwAN6CY1RlMC0uIWDY14kR6zwREUL406vaom72HAX84sDN 5 | 4oopSkImWdptW6Jsw8wqGmJpXKkzK+2iIUQiNnNHoGK06l6Qd5h3Tp06mRjsSGqV 6 | /hp8T99CHmratWIfHKCC37ykrIrdr2qIFPFOYJ2U2z6Wn3qd7qFqZGK5I4qXbGTb 7 | V8Wu3mGSld7UxxJai+kud6p+fEoELEaDs4NCG+NKbjC9k6ynfdNrzwnVPuMLiG9q 8 | F6DIUHE73X/CLs60EXUxocR0YzziqZVGLsxmVZsM74gC/BM9b+n6vkB8tsKgBaS1 9 | WETquRljmEcGG9x6BOlwOnwiKmvT87PN3KHXBzXqmwLoybfcb0XXFHws/LRK3Nx6 10 | RsufNh56zq6bjJeuC3eZtCCqQaVuiZo3vcnPGaXnZ7O/V8ZoA62kyoqHHHU4o6Yw 11 | ncbIcg334bri5bNBLoTJ4/DYE8222Ta5XSyWaZCURRsfpGtUpk+51F91Yec/gexP 12 | MGCysDBN1wZ4Zz8DHlO69M0I3CwLlGc5jLMSge9nqoT2Ar3kok8D63QELZcCAwEA 13 | AQKCAgA7aYPvepxCB5bohsGWhbAzzUkJZzgJabfjIQN0eUjVmJhcTGw9IKUJSIZm 14 | OIMOlsxxuf/Y+1RhQIyopVHrjNJYoH9snMdlauzI59BzmHDK4+tod44V5VANi9AX 15 | nOF6BlcO31HNU3GIuNICBczDq0l/aQMaQg6SCCMoTT4CQvMA9UiH9Kq5tZvsCgVh 16 | RR4VX+aVgMR3lOfUHbkG9+2ZrWLT28hvlfoz2itp/5npz2jmWIzKtpThNjPyM+fl 17 | 50D031zArdhe7XsQd28/bf3Vaab8FzewOt5WWniaKCA85R7QqTMVQx765RwYW9VT 18 | FD1FB3jjyIo4MP+0lgkoDD3I5KSjWXwMIkBNVYsaYi+Xz4gCwszRpUd3608M19IQ 19 | xUOK+Mxmg7+Xl+O6jYRzP32npl+hhofiQYDPaFFzn46XnkWpT6M7hrDOU8FZdklz 20 | LMMKQQ0vUoAYExv13htTkU+WL1xPteA46NXyXwIPW1Ieo7YcTjcB4DbsENLZNkGF 21 | yZD8tFecS4GeeJJIx+JGiZuO2GHQm2z27eqc41POyLS+uxVTUXKTkGbQvdeSb6w3 22 | 48xKoCLm8L93jyawxCVfH+pEJS9M7zo/8ecTbbV3U5D82ODVSqjmNOplaB5J0fQE 23 | hQx7AWc+muS5bei3B7enBC5lPpwttBaMEu0ay1MubUhoGOhcAQKCAQEA44a5FT7J 24 | VC4NKItUR4LTzRvFMYGvC+kWuJOVwEaj3VVjIBLLUaObhquJ4YHxULfJ9p8pmUj2 25 | V/W4p7SJHaT5iWWjgQI/bMGIy0afhHso8xh1dTTIr4PQSwnFbQ32zrwyPrlhYsTf 26 | 5T29Sm7BWj6IZBs0nvCK1vWB7U8xUDA3I5KobVEpsTFH1UMUlBUo68ziJbOvUDoR 27 | ndYAy17cHddcFNHSazbWzGoNWpkcL/KMnThex1GzwVIDchk6mte4r1fd09JbK3gB 28 | t0CV1dPdWKavYRdUr+CWXlxadLFPCz0D7PIk9AUXTXJW41sveKKBuTpAI6afi0IV 29 | c5str8HUsXA9gQKCAQEAkunyluhAC4zpQZwXu1pDKMIWZM4GjZnTBZ8Js9a+/5d7 30 | 9JMMOnhwNFFr1UYnQ+u9NbTiHP1jbxuosLmYTQAgNnnrGkmqnDUGe59G7oMyVe7C 31 | ubSsu4Rq3jILAR3axsFrjy3NNQLivZm65gBc1bnYpmsQQtHGmmTezDk2diiGNDup 32 | ENNkZyfsXivQZut2gwDwEHK/RCfQA68UHipCNs69QyDTMk0/F2rJmKGiWECc1X9k 33 | rEd1QQR3w4Iet9JcamWSTwzZc7K3O0yT/LG7MP7+hXxVxnib14THiA1iKiGHq3d6 34 | IM5zDt4k/h2AVhOl8N61ysGOe4emEQ+Cj1WvUZAnFwKCAQEAzlBk1in339heYCxv 35 | QOUV78BFwI2K0C8NRlO1kAO+JT5/Qx8ntKC5r5Uu0wjEbGArx/EthGyPzNTpG1Fu 36 | oC3vhLJgX+RM5O5df45LqZMQX9cG8z/o1padMt3qYugtq+slWJE7CJfjOnkQg0UJ 37 | GS7o+HVe8tzF2QQIS8rquX7vENe02GOnfaBlNbG9IEZLs/419uAHkaUGQmxCjic3 38 | S+vz+IEG3+d7QSLNdyCtWaED9rCd6PliGWOn8jeEV9JTCtSPNrthpnoMfEIZXCrg 39 | ZLnJAC5qwYzSbUArWfNJ7LPoMlykO42+QqDyvvj5g9c/8FksveciduF2mDzXYa9O 40 | kZNogQKCAQEAkEelcMLCMxW99is/u0VX82045OLY2LOa5EheFPnvNcAlgfnv5nRl 41 | bVwRFLEC2tdnSJlN/r5yqql1L6n1gpl/CUEOvRBft2zz4vB3jsHV60LChfKEONxA 42 | v9pRqFUTiGJoKYMHpuogl6ekP0FX6qXLuRQoMhcmfnZVwCbn73643g9BaD7SueQh 43 | ZBKPZqQUDXAcU2r9oAehaBzHGyDRSlYa1RQllZ77ORosxfLnJti9rYag7fh3lNS4 44 | cY8Wb9zt2afK2kt6Ov/mpxv7sg0yE1o5yAplirbkBfJmqpzKLSokvSZnEFTv9kf/ 45 | +Hgsk1xUeYue6XLRZUvAsbyTsgSqWuXBHQKCAQEA0vDAx7FX5Wi7LSTUb3Bz1GN9 46 | jMWqNyQmJzsY68CzfbKDOcnkeJwm5BXUk5FsYKIemoaGfNNpoDze/QSvbLsf0DNr 47 | 1yDHscNC8qZF7g5X3t51e1WfEjGWQ5EOTfXqqmJARoj0OQm7Z+wUid6nIhi83SBD 48 | a+PfC9j4ieJ6XNs2gzbTZZN/bKZV9Cx3o4TeO95ihYXJEmB/ki8DTgEf/uJm6+bH 49 | 08VPR8wtQE9FF1tETbgL5tcGMDthrSBafFiuBs95czipbipyq+Zp/9Tmw68EYUg6 50 | LUSjuo6CbwtYCnr99zWDLwJJEXVfEaN8ArYyXiXGjZVjW0J/BR/9MKavwA1iwA== 51 | -----END RSA PRIVATE KEY----- 52 | -------------------------------------------------------------------------------- /tests/docker-ssh-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster-slim 2 | 3 | ### 4 | ### Install SSH Server 5 | ### 6 | RUN set -eux \ 7 | && apt update \ 8 | && apt install -y \ 9 | rsync \ 10 | openssh-server 11 | 12 | ### 13 | ### Configure SSH 14 | ### 15 | RUN set -eux \ 16 | && mkdir -p /var/run/sshd \ 17 | && chmod 0755 /var/run/sshd \ 18 | \ 19 | && mkdir -p /root/.ssh \ 20 | && chmod 0700 /root/.ssh 21 | 22 | ### 23 | ### Add public key 24 | ### 25 | COPY id_rsa.pub /root/.ssh/authorized_keys 26 | RUN set -eux && chmod 0400 /root/.ssh/authorized_keys 27 | 28 | ### 29 | ### Add backup directories 30 | ### 31 | RUN set -eux \ 32 | && mkdir -p /root/backup1 \ 33 | && mkdir -p /backup2 34 | 35 | CMD ["/usr/sbin/sshd", "-D"] 36 | -------------------------------------------------------------------------------- /tests/docker-ssh-server/README.md: -------------------------------------------------------------------------------- 1 | # Docker SSH server 2 | 3 | ## Note 4 | 5 | The bundled ssh public key is soley for the purpose of this Docker image and has not accidentally 6 | been leaked :-) 7 | -------------------------------------------------------------------------------- /tests/docker-ssh-server/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCCksLIDHaCuoodKx0zDnIoJ854q7WOw4oexptUaZrTnIkf8T0aYVYa+EVa0Xsq5+Ktvmzhow4ViexePoUJxqKb/mu7bQ/ZbCdRLvQdDwtB8A1K62sVJdvUsmg3DeqzP/vJYvAA3oJjVGUwLS4hYNjXiRHrPBERQvjTq9qibvYcBfziwM3iiilKQiZZ2m1bomzDzCoaYmlcqTMr7aIhRCI2c0egYrTqXpB3mHdOnTqZGOxIapX+GnxP30Ieatq1Yh8coILfvKSsit2vaogU8U5gnZTbPpafep3uoWpkYrkjipdsZNtXxa7eYZKV3tTHElqL6S53qn58SgQsRoOzg0Ib40puML2TrKd902vPCdU+4wuIb2oXoMhQcTvdf8IuzrQRdTGhxHRjPOKplUYuzGZVmwzviAL8Ez1v6fq+QHy2wqAFpLVYROq5GWOYRwYb3HoE6XA6fCIqa9Pzs83codcHNeqbAujJt9xvRdcUfCz8tErc3HpGy582HnrOrpuMl64Ld5m0IKpBpW6Jmje9yc8Zpedns79XxmgDraTKioccdTijpjCdxshyDffhuuLls0EuhMnj8NgTzbbZNrldLJZpkJRFGx+ka1SmT7nUX3Vh5z+B7E8wYLKwME3XBnhnPwMeU7r0zQjcLAuUZzmMsxKB72eqhPYCveSiTwPrdAQtlw== 2 | --------------------------------------------------------------------------------