77from deploy .build import Build
88from deploy .config import Config
99from deploy .links import make_links
10- from deploy .sync import do_sync
10+ from deploy .sync import Sync , do_sync , change_prefix
1111
1212BUILD_SCRIPT = """\
1313 #!/usr/bin/env bash
1616echo "hello world">>$out/bin/a_file
1717"""
1818
19- RSH = [
20- "python" ,
21- "-c" ,
22- "import sys, os; args = sys.argv[sys.argv.index('--')+1:]; os.execvp(args[0], args)" ,
23- ]
2419
20+ @pytest .fixture (autouse = True )
21+ def fake_ssh (monkeypatch : pytest .MonkeyPatch ) -> None :
22+ """Override Sync's SSH command so that it doesn't use SSH, and instead
23+ executes the command locally
2524
26- def mocked_format_dest_path (area , path , dest ):
27- # Original function defines this as area.host:path, where area will be
28- # the same in both source and destination. We mock this setup and
29- # disregard the host (i.e. no ssh) and allow a different destination
30- # instead of source
31- # We wrap this function in a lambda that passes on dest (as that is
32- # not included in the original one. Similar behavoir as partial,
33- # without including functools
34- return dest
25+ """
3526
36-
37- def setup_local_sync (monkeypatch : pytest .MonkeyPatch , destination : str ) -> None :
38- import deploy .sync
39-
40- def format_dest_path (* _ ) -> str :
41- return destination
42-
43- monkeypatch .setattr (deploy .sync .Sync , "_format_dest_path" , format_dest_path )
44- monkeypatch .setattr (deploy .sync , "RSH" , RSH )
27+ # We replace RSH with an inline sh script. Both rsync and our `Sync._bash`
28+ # set the first argument to be the destination hostname. The remainder is
29+ # the command to execute on the "remote server". We simply execute it
30+ # locally. Then, sh sets the next argument ("fake_ssh") to be the program
31+ # name ($0), which is why we specify it.
32+ monkeypatch .setattr (Sync , "RSH" , ["/bin/sh" , "-c" , 'shift; exec "$@"' , "fake_ssh" ])
4533
4634
4735@pytest .fixture
@@ -56,7 +44,7 @@ def base_config(tmp_path):
5644 },
5745 ],
5846 "envs" : [{"name" : "A" , "dest" : "location" }],
59- "areas" : [{"name" : "destination" , "host" : "localhost " }],
47+ "areas" : [{"name" : "destination" , "host" : "example.com " }],
6048 "links" : {"location" : {"latest" : "^" }},
6149 }
6250
@@ -74,9 +62,40 @@ def _deploy_config(config, configpath, prefix=None):
7462 return builder
7563
7664
77- def test_successful_sync (tmp_path , monkeypatch , base_config ):
65+ @pytest .mark .parametrize (
66+ "old_prefix, new_prefix, path, expectation" ,
67+ [
68+ pytest .param (
69+ "/foo" ,
70+ "/bar" ,
71+ "/foo/file" ,
72+ "/bar/file" ,
73+ id = "Simple" ,
74+ ),
75+ pytest .param (
76+ "/some/prefix" ,
77+ "/yet/another/new/prefix" ,
78+ "/some/prefix/path/in/prefix" ,
79+ "/yet/another/new/prefix/path/in/prefix" ,
80+ id = "Longer path" ,
81+ ),
82+ pytest .param ("/foo" , "/bar" , "/bar/file" , ValueError , id = "Invalid prefix" ),
83+ ],
84+ )
85+ def test_change_prefix (old_prefix , new_prefix , path , expectation ):
86+ path = Path (path )
87+ old_prefix = Path (old_prefix )
88+ new_prefix = Path (new_prefix )
89+
90+ if isinstance (expectation , type ) and issubclass (expectation , BaseException ):
91+ with pytest .raises (expectation ):
92+ change_prefix (path , old_prefix , new_prefix )
93+ else :
94+ assert change_prefix (path , old_prefix , new_prefix ) == Path (expectation )
95+
96+
97+ def test_successful_sync (tmp_path , base_config ):
7898 destination = tmp_path / "destination"
79- setup_local_sync (monkeypatch , str (destination ))
8099
81100 builder = _deploy_config (base_config , tmp_path )
82101
@@ -99,18 +118,17 @@ def test_successful_sync(tmp_path, monkeypatch, base_config):
99118 assert os .path .islink (destination / "location/latest" )
100119
101120
102- def test_failing_sync (tmp_path , monkeypatch , base_config ):
121+ def test_failing_sync (tmp_path , base_config ):
103122 """Try to sync to non existent area"""
104- setup_local_sync (monkeypatch , "/non-existent/destination" )
105-
106123 _deploy_config (base_config , tmp_path )
107124 with pytest .raises (
108125 CalledProcessError ,
109- match = "' /non-existent/destination'\ \ )' returned non-zero exit status 11." ,
126+ match = r"'example.com: /non-existent/destination'\)' returned non-zero exit status 11." ,
110127 ):
111128 do_sync (
112129 configpath = tmp_path ,
113130 config = base_config ,
114131 extra_scripts = tmp_path ,
115132 prefix = tmp_path ,
133+ dest_prefix = Path ("/non-existent/destination" ),
116134 )
0 commit comments