11
11
SERVER_URL = os .environ .get ('TEST_MERGIN_URL' )
12
12
API_USER = os .environ .get ('TEST_API_USERNAME' )
13
13
USER_PWD = os .environ .get ('TEST_API_PASSWORD' )
14
+ API_USER2 = os .environ .get ('TEST_API_USERNAME2' )
15
+ USER_PWD2 = os .environ .get ('TEST_API_PASSWORD2' )
14
16
TMP_DIR = tempfile .gettempdir ()
15
17
TEST_DATA_DIR = os .path .join (os .path .dirname (os .path .realpath (__file__ )), 'test_data' )
16
18
CHANGED_SCHEMA_DIR = os .path .join (os .path .dirname (os .path .realpath (__file__ )), 'modified_schema' )
@@ -22,8 +24,16 @@ def toggle_geodiff(enabled):
22
24
23
25
@pytest .fixture (scope = 'function' )
24
26
def mc ():
25
- assert SERVER_URL and SERVER_URL .rstrip ('/' ) != 'https://public.cloudmergin.com' and API_USER and USER_PWD
26
- return MerginClient (SERVER_URL , login = API_USER , password = USER_PWD )
27
+ return create_client (API_USER , USER_PWD )
28
+
29
+ @pytest .fixture (scope = 'function' )
30
+ def mc2 ():
31
+ return create_client (API_USER2 , USER_PWD2 )
32
+
33
+
34
+ def create_client (user , pwd ):
35
+ assert SERVER_URL and SERVER_URL .rstrip ('/' ) != 'https://public.cloudmergin.com' and user and pwd
36
+ return MerginClient (SERVER_URL , login = user , password = pwd )
27
37
28
38
29
39
def cleanup (mc , project , dirs ):
@@ -32,6 +42,11 @@ def cleanup(mc, project, dirs):
32
42
mc .delete_project (project )
33
43
except ClientError :
34
44
pass
45
+ remove_folders (dirs )
46
+
47
+
48
+ def remove_folders (dirs ):
49
+ # clean given directories
35
50
for d in dirs :
36
51
if os .path .exists (d ):
37
52
shutil .rmtree (d )
@@ -461,6 +476,7 @@ def test_empty_file_in_subdir(mc):
461
476
mc .pull_project (project_dir_2 )
462
477
assert os .path .exists (os .path .join (project_dir_2 , 'subdir2' , 'empty2.txt' ))
463
478
479
+
464
480
def test_clone_project (mc ):
465
481
test_project = 'test_clone_project'
466
482
test_project_fullname = API_USER + '/' + test_project
@@ -483,3 +499,148 @@ def test_clone_project(mc):
483
499
mc .clone_project (test_project_fullname , cloned_project_name , API_USER )
484
500
projects = mc .projects_list (flag = 'created' )
485
501
assert any (p for p in projects if p ['name' ] == cloned_project_name and p ['namespace' ] == API_USER )
502
+
503
+
504
+ def test_set_read_write_access (mc ):
505
+ test_project = 'test_set_read_write_access'
506
+ test_project_fullname = API_USER + '/' + test_project
507
+
508
+ # cleanups
509
+ project_dir = os .path .join (TMP_DIR , test_project , API_USER )
510
+ cleanup (mc , test_project_fullname , [project_dir ])
511
+
512
+ # create new (empty) project on server
513
+ mc .create_project (test_project )
514
+
515
+ # Add writer access to another client
516
+ project_info = get_project_info (mc , API_USER , test_project )
517
+ access = project_info ['access' ]
518
+ access ['writersnames' ].append (API_USER2 )
519
+ access ['readersnames' ].append (API_USER2 )
520
+ mc .set_project_access (test_project_fullname , access )
521
+
522
+ # check access
523
+ project_info = get_project_info (mc , API_USER , test_project )
524
+ access = project_info ['access' ]
525
+ assert API_USER2 in access ['writersnames' ]
526
+ assert API_USER2 in access ['readersnames' ]
527
+
528
+
529
+ def test_available_storage_validation (mc ):
530
+ """
531
+ Testing of storage limit - applies to user pushing changes into own project (namespace matching username).
532
+ This test also tests giving read and write access to another user. Additionally tests also uploading of big file.
533
+ """
534
+ test_project = 'test_available_storage_validation'
535
+ test_project_fullname = API_USER + '/' + test_project
536
+
537
+ # cleanups
538
+ project_dir = os .path .join (TMP_DIR , test_project , API_USER )
539
+ cleanup (mc , test_project_fullname , [project_dir ])
540
+
541
+ # create new (empty) project on server
542
+ mc .create_project (test_project )
543
+
544
+ # download project
545
+ mc .download_project (test_project_fullname , project_dir )
546
+
547
+ # get user_info about storage capacity
548
+ user_info = mc .user_info ()
549
+ storage_remaining = user_info ['storage' ] - user_info ['disk_usage' ]
550
+
551
+ # generate dummy data (remaining storage + extra 1024b)
552
+ dummy_data_path = project_dir + "/data"
553
+ file_size = storage_remaining + 1024
554
+ _generate_big_file (dummy_data_path , file_size )
555
+
556
+ # try to upload
557
+ got_right_err = False
558
+ try :
559
+ mc .push_project (project_dir )
560
+ except ClientError as e :
561
+ # Expecting "Storage limit has been reached" error msg.
562
+ assert str (e ).startswith ("Storage limit has been reached" )
563
+ got_right_err = True
564
+ assert got_right_err
565
+
566
+ # Expecting empty project
567
+ project_info = get_project_info (mc , API_USER , test_project )
568
+ assert project_info ['meta' ]['files_count' ] == 0
569
+ assert project_info ['meta' ]['size' ] == 0
570
+
571
+
572
+ def test_available_storage_validation2 (mc , mc2 ):
573
+ """
574
+ Testing of storage limit - should not be applied for user pushing changes into project with different namespace.
575
+ This should cover the exception of mergin-py-client that a user can push changes to someone else's project regardless
576
+ the user's own storage limitation. Of course, other limitations are still applied (write access, owner of
577
+ a modified project has to have enough free storage).
578
+
579
+ Therefore NOTE that there are following assumptions:
580
+ - API_USER2's free storage >= API_USER's free storage + 1024b (size of changes to be pushed)
581
+ - both accounts should ideally have a free plan
582
+ """
583
+ test_project = 'test_available_storage_validation2'
584
+ test_project_fullname = API_USER2 + '/' + test_project
585
+
586
+ # cleanups
587
+ project_dir = os .path .join (TMP_DIR , test_project , API_USER )
588
+ cleanup (mc , test_project_fullname , [project_dir ])
589
+ cleanup (mc2 , test_project_fullname , [project_dir ])
590
+
591
+ # create new (empty) project on server
592
+ mc2 .create_project (test_project )
593
+
594
+ # Add writer access to another client
595
+ project_info = get_project_info (mc2 , API_USER2 , test_project )
596
+ access = project_info ['access' ]
597
+ access ['writersnames' ].append (API_USER )
598
+ access ['readersnames' ].append (API_USER )
599
+ mc2 .set_project_access (test_project_fullname , access )
600
+
601
+ # download project
602
+ mc .download_project (test_project_fullname , project_dir )
603
+
604
+ # get user_info about storage capacity
605
+ user_info = mc .user_info ()
606
+ storage_remaining = user_info ['storage' ] - user_info ['disk_usage' ]
607
+
608
+ # generate dummy data (remaining storage + extra 1024b)
609
+ dummy_data_path = project_dir + "/data"
610
+ file_size = storage_remaining + 1024
611
+ _generate_big_file (dummy_data_path , file_size )
612
+
613
+ # try to upload
614
+ mc .push_project (project_dir )
615
+
616
+ # Check project content
617
+ project_info = get_project_info (mc2 , API_USER2 , test_project )
618
+ assert project_info ['meta' ]['files_count' ] == 1
619
+ assert project_info ['meta' ]['size' ] == file_size
620
+
621
+ # remove dummy big file from a disk
622
+ remove_folders ([project_dir ])
623
+
624
+
625
+ def get_project_info (mc , namespace , project_name ):
626
+ """
627
+ Returns first (and suppose to be just one) project info dict of project matching given namespace and name.
628
+ :param mc: MerginClient instance
629
+ :param namespace: project's namespace
630
+ :param project_name: project's name
631
+ :return: dict with project info
632
+ """
633
+ projects = mc .projects_list (flag = 'created' )
634
+ test_project_list = [p for p in projects if p ['name' ] == project_name and p ['namespace' ] == namespace ]
635
+ assert len (test_project_list ) == 1
636
+ return test_project_list [0 ]
637
+
638
+
639
+ def _generate_big_file (filepath , size ):
640
+ """
641
+ generate big binary file with the specified size in bytes
642
+ :param filepath: full filepath
643
+ :param size: the size in bytes
644
+ """
645
+ with open (filepath , 'wb' ) as fout :
646
+ fout .write (b"\0 " * size )
0 commit comments