Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: test sync include/exclude options. #4452

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 10 additions & 16 deletions .github/scripts/hypo/syncrand.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,15 @@
from fs_op import FsOperation
import random

st_entry_name = st.text(alphabet='abc', min_size=1, max_size=3)
st_patterns = st.text(alphabet='abc?/*', min_size=1, max_size=5).\
filter(lambda s: s.find('***') == -1 or s.endswith('/***'))
st_patterns = st.lists(st.sampled_from(['a','?','/','*', '/***']), min_size=1, max_size=10)\
.map(''.join).filter(lambda s: s.find('***') == -1 or (s.count('/***')==1 and s.endswith('a/***')))
st_entry_name = st.text(alphabet='abc*?', min_size=1, max_size=4)
st_patterns = st.lists(st.sampled_from(['a','?','/','*']), min_size=1, max_size=10)\
.map(''.join).filter(lambda s: s.find('***') == -1 )
st_patterns = st.lists(st.sampled_from(['a','?','/','*']), min_size=1, max_size=10)\
.map(''.join).filter(lambda s: s.find('**') == -1 )
.map(''.join).filter(lambda s: s.find('***') == -1 or (s.count('***') == 1 and s.endswith('/***')))

st_option = st.fixed_dictionaries({
"option": st.just("--include") | st.just("--exclude"),
"pattern": st_patterns
})
st_options = st.lists(st_option, min_size=1, max_size=10).\
filter(lambda self: any(item["pattern"].endswith('/***') for item in self))

st_options = st.lists(st_option, min_size=1, max_size=10)

SEED=int(os.environ.get('SEED', random.randint(0, 1000000000)))
Expand All @@ -42,7 +35,7 @@ class SyncMachine(RuleBasedStateMachine):
DEST_JUICESYNC = '/tmp/juicesync'
log_level = os.environ.get('LOG_LEVEL', 'INFO')
logger = common.setup_logger(f'./syncrand.log', 'syncrand_logger', log_level)
fsop = FsOperation(logger)
fsop = FsOperation({ROOT_DIR1: logger, ROOT_DIR2: logger})

@initialize(target=Folders)
def init_folders(self):
Expand Down Expand Up @@ -109,11 +102,12 @@ def mkdir(self, parent, subdir, mode, user='root', umask=0o022):
def sync(self, options):
subprocess.check_call(['rm', '-rf', self.DEST_RSYNC])
subprocess.check_call(['rm', '-rf', self.DEST_JUICESYNC])
options = ' '.join([f'{item["option"]} {item["pattern"]}' for item in options])
self.logger.info(f'rsync -r -vvv {self.ROOT_DIR1}/ {self.DEST_RSYNC}/ {options}')
subprocess.check_call(f'rsync -r -vvv {self.ROOT_DIR1}/ {self.DEST_RSYNC}/ {options}'.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.logger.info(f'./juicefs sync --dirs -v {self.ROOT_DIR1}/ {self.DEST_JUICESYNC}/ {options}')
subprocess.check_call(f'./juicefs sync --dirs -v {self.ROOT_DIR1}/ {self.DEST_JUICESYNC}/ {options}'.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
options_run = ' '.join([f'{item["option"]} {item["pattern"]}' for item in options])
options_display = ' '.join([f'{item["option"]} "{item["pattern"]}"' for item in options])
self.logger.info(f'rsync -r -vvv {self.ROOT_DIR1}/ {self.DEST_RSYNC}/ {options_display}')
subprocess.check_call(f'rsync -r -vvv {self.ROOT_DIR1}/ {self.DEST_RSYNC}/ {options_run}'.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.logger.info(f'./juicefs sync --dirs -v {self.ROOT_DIR1}/ {self.DEST_JUICESYNC}/ {options_display}')
subprocess.check_call(f'./juicefs sync --dirs -v {self.ROOT_DIR1}/ {self.DEST_JUICESYNC}/ {options_run}'.split(), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
subprocess.check_call(['diff', '-r', self.DEST_RSYNC, self.DEST_JUICESYNC])
except subprocess.CalledProcessError as e:
Expand Down
32 changes: 32 additions & 0 deletions .github/scripts/hypo/syncrand_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,37 @@ def test_sync5(self):
{'option': '--exclude', 'pattern': 'a?**'}])
state.teardown()

def test_sync6(self):
state = SyncMachine()
v1 = state.init_folders()
v2 = state.create_file(content=b'', file_name='a', mode='w', parent=v1, umask=0)
state.sync(options=[{'option': '--exclude', 'pattern': '**a'}])
state.teardown()

def test_sync7(self):
state = SyncMachine()
v1 = state.init_folders()
v2 = state.create_file(content=b'', file_name='aa', mode='w', parent=v1, umask=0)
state.sync(options=[{'option': '--exclude', 'pattern': 'aa**a'}])
state.teardown()

def test_sync8(self):
# SEE: https://github.com/juicedata/juicefs/issues/4471
state = SyncMachine()
v1 = state.init_folders()
v2 = state.mkdir(mode=8, parent=v1, subdir='a', umask=0)
state.sync(options=[{'option': '--exclude', 'pattern': 'a/**/a'}])
state.teardown()

def test_sync9(self):
# SEE: https://github.com/juicedata/juicefs/issues/4471
state = SyncMachine()
v1 = state.init_folders()
v2 = state.mkdir(mode=8, parent=v1, subdir='aa', umask=0)
v3 = state.create_file(content=b'', file_name='a', mode='w', parent=v2, umask=0)
state.sync(options=[{'option': '--include', 'pattern': '**aa**'},
{'option': '--exclude', 'pattern': 'a'}])
state.teardown()

if __name__ == '__main__':
unittest.main()
2 changes: 1 addition & 1 deletion .github/scripts/sync/sync_fsrand.sh
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ test_list_threads(){
check_diff $DEST_DIR1 $DEST_DIR2
}

test_update(){
skip_test_update(){
prepare_test
./juicefs mount $META_URL /tmp/jfs -d
sync_option="--dirs --perms --check-all --links --list-threads 10 --list-depth 5"
Expand Down
18 changes: 18 additions & 0 deletions .github/scripts/sync/sync_minio.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,25 @@ prepare_test(){
./juicefs mount -d $META_URL /jfs
lsof -i :9005 | awk 'NR!=1 {print $2}' | xargs -r kill -9 || true
MINIO_ROOT_USER=minioadmin MINIO_ROOT_PASSWORD=minioadmin ./juicefs gateway $META_URL localhost:9005 &
wait_gateway_ready
./mc alias set juicegw http://localhost:9005 minioadmin minioadmin --api S3v4
}

wait_gateway_ready(){
timeout=30
for i in $(seq 1 $timeout); do
if [[ -z $(lsof -i :9005) ]]; then
echo "$i Waiting for port 9005 to be ready..."
sleep 1
else
echo "gateway is now ready on port 9005"
break
fi
done
if [[ -z $(lsof -i :9005) ]]; then
echo "gateway is not ready after $timeout seconds"
exit 1
fi
}

source .github/scripts/common/run_test.sh && run_test $@
75 changes: 48 additions & 27 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ on:
jobs:
sync:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
type: ['sync', 'sync_fsrand', 'sync_minio', 'sync_cluster', 'sync_exclude']
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -41,40 +45,57 @@ jobs:

- name: Build
uses: ./.github/actions/build
# with:
# useBeta: true

- name: Test Sync
timeout-minutes: 30
run: |
sudo META=redis .github/scripts/sync/sync.sh

- name: Test Sync with fsrand
timeout-minutes: 30
run: |
sudo META=redis .github/scripts/sync/sync_fsrand.sh

- name: Test Sync with mino
timeout-minutes: 30
run: |
sudo META=redis .github/scripts/sync/sync_minio.sh

- name: Test Sync with multi workers
timeout-minutes: 30
run: |
# not supported algo: "dsa" "ecdsa-sk" "ed25519-sk"
types=("ecdsa" "ed25519" "rsa")
random_type=${types[$RANDOM % ${#types[@]}]}
sudo CI=true META=redis KEY_TYPE=$random_type .github/scripts/sync/sync_cluster.sh

- name: Test sync include/exclude option
timeout-minutes: 30
run: |
# sudo python3 .github/scripts/hypo/syncrand_test.py
sudo LOG_LEVEL=WARNING PROFILE=ci python3 .github/scripts/hypo/syncrand.py
if [[ "${{matrix.type}}" == 'sync' ]]; then
sudo META=redis .github/scripts/sync/sync.sh
elif [[ "${{matrix.type}}" == 'sync_fsrand' ]]; then
sudo META=redis .github/scripts/sync/sync_fsrand.sh
elif [[ "${{matrix.type}}" == 'sync_minio' ]]; then
sudo META=redis .github/scripts/sync/sync_minio.sh
elif [[ "${{matrix.type}}" == 'sync_cluster' ]]; then
types=("ecdsa" "ed25519" "rsa")
random_type=${types[$RANDOM % ${#types[@]}]}
sudo CI=true META=redis KEY_TYPE=$random_type .github/scripts/sync/sync_cluster.sh
elif [[ "${{matrix.type}}" == 'sync_exclude' ]]; then
sudo python3 .github/scripts/hypo/syncrand_test.py
if [ "${{github.event_name}}" == "pull_request" ]; then
sudo MAX_EXAMPLE=100 STEP_COUNT=50 LOG_LEVEL=WARNING PROFILE=ci python3 .github/scripts/hypo/syncrand.py
else
sudo MAX_EXAMPLE=1000 STEP_COUNT=200 LOG_LEVEL=WARNING PROFILE=ci python3 .github/scripts/hypo/syncrand.py
fi
else
echo "Unknown type: ${{matrix.type}}"
exit 1
fi

- name: Setup upterm session
if: failure() && (github.event.inputs.debug == 'true' || github.run_attempt != 1)
# if: failure()
timeout-minutes: 60
uses: lhotari/action-upterm@v1

success-all-test:
runs-on: ubuntu-latest
needs: [sync]
if: always()
steps:
- uses: technote-space/workflow-conclusion-action@v3
- uses: actions/checkout@v3

- name: Check Failure
if: env.WORKFLOW_CONCLUSION == 'failure'
run: exit 1

- name: Send Slack Notification
if: failure() && github.event_name != 'workflow_dispatch'
uses: juicedata/slack-notify-action@main
with:
channel-id: "${{ secrets.SLACK_CHANNEL_ID_FOR_PR_CHECK_NOTIFY }}"
slack_bot_token: "${{ secrets.SLACK_BOT_TOKEN }}"

- name: Success
if: success()
run: echo "All Done"
Loading