22// The .NET Foundation licenses this file to you under the MIT license.
33
44using System ;
5+ using System . Collections . Generic ;
56using System . IO ;
67using System . Linq ;
8+ using System . Runtime . InteropServices ;
79
810using FluentAssertions ;
911using Microsoft . DotNet . Cli . Build . Framework ;
@@ -21,6 +23,165 @@ public SymbolicLinks(SymbolicLinks.SharedTestState fixture)
2123 sharedTestState = fixture ;
2224 }
2325
26+ [ Theory ]
27+ [ InlineData ( "a/b/SymlinkToFrameworkDependentApp" ) ]
28+ [ InlineData ( "a/SymlinkToFrameworkDependentApp" ) ]
29+ public void Symlink_all_files_fx ( string symlinkRelativePath )
30+ {
31+ using var testDir = TestArtifact . Create ( "symlink" ) ;
32+ Directory . CreateDirectory ( Path . Combine ( testDir . Location , Path . GetDirectoryName ( symlinkRelativePath ) ) ) ;
33+
34+ // Symlink every file in the app directory
35+ var symlinks = new List < SymLink > ( ) ;
36+ try
37+ {
38+ foreach ( var file in Directory . EnumerateFiles ( sharedTestState . FrameworkDependentApp . Location ) )
39+ {
40+ var fileName = Path . GetFileName ( file ) ;
41+ var symlinkPath = Path . Combine ( testDir . Location , symlinkRelativePath , fileName ) ;
42+ Directory . CreateDirectory ( Path . GetDirectoryName ( symlinkPath ) ) ;
43+ symlinks . Add ( new SymLink ( symlinkPath , file ) ) ;
44+ }
45+
46+ var result = Command . Create ( Path . Combine ( testDir . Location , symlinkRelativePath , Path . GetFileName ( sharedTestState . FrameworkDependentApp . AppExe ) ) )
47+ . CaptureStdErr ( )
48+ . CaptureStdOut ( )
49+ . DotNetRoot ( TestContext . BuiltDotNet . BinPath )
50+ . Execute ( ) ;
51+
52+ // This should succeed on all platforms, but for different reasons:
53+ // * Windows: The apphost will look next to the symlink for the app dll and find the symlinked dll
54+ // * Unix: The apphost will look next to the resolved apphost for the app dll and find the real thing
55+ result
56+ . Should ( ) . Pass ( )
57+ . And . HaveStdOutContaining ( "Hello World" ) ;
58+ }
59+ finally
60+ {
61+ foreach ( var symlink in symlinks )
62+ {
63+ symlink . Dispose ( ) ;
64+ }
65+ }
66+ }
67+
68+ [ Theory ]
69+ [ InlineData ( "a/b/SymlinkToFrameworkDependentApp" ) ]
70+ [ InlineData ( "a/SymlinkToFrameworkDependentApp" ) ]
71+ public void Symlink_split_files_fx ( string symlinkRelativePath )
72+ {
73+ using var testDir = TestArtifact . Create ( "symlink" ) ;
74+
75+ // Split the app into two directories, one for the apphost and one for the rest of the files
76+ var appHostDir = Path . Combine ( testDir . Location , "apphost" ) ;
77+ var appFilesDir = Path . Combine ( testDir . Location , "appfiles" ) ;
78+ Directory . CreateDirectory ( appHostDir ) ;
79+ Directory . CreateDirectory ( appFilesDir ) ;
80+
81+ var appHostName = Path . GetFileName ( sharedTestState . FrameworkDependentApp . AppExe ) ;
82+
83+ File . Copy (
84+ sharedTestState . FrameworkDependentApp . AppExe ,
85+ Path . Combine ( appHostDir , appHostName ) ) ;
86+
87+ foreach ( var file in Directory . EnumerateFiles ( sharedTestState . FrameworkDependentApp . Location ) )
88+ {
89+ var fileName = Path . GetFileName ( file ) ;
90+ if ( fileName != appHostName )
91+ {
92+ File . Copy ( file , Path . Combine ( appFilesDir , fileName ) ) ;
93+ }
94+ }
95+
96+ // Symlink all of the above into a single directory
97+ var targetPath = Path . Combine ( testDir . Location , symlinkRelativePath ) ;
98+ Directory . CreateDirectory ( targetPath ) ;
99+ var symlinks = new List < SymLink > ( ) ;
100+ try
101+ {
102+ foreach ( var file in Directory . EnumerateFiles ( appFilesDir ) )
103+ {
104+ var fileName = Path . GetFileName ( file ) ;
105+ var symlinkPath = Path . Combine ( targetPath , fileName ) ;
106+ Directory . CreateDirectory ( Path . GetDirectoryName ( symlinkPath ) ) ;
107+ symlinks . Add ( new SymLink ( symlinkPath , file ) ) ;
108+ }
109+ symlinks . Add ( new SymLink (
110+ Path . Combine ( targetPath , appHostName ) ,
111+ Path . Combine ( appHostDir , appHostName ) ) ) ;
112+
113+ var result = Command . Create ( Path . Combine ( targetPath , appHostName ) )
114+ . CaptureStdErr ( )
115+ . CaptureStdOut ( )
116+ . DotNetRoot ( TestContext . BuiltDotNet . BinPath )
117+ . Execute ( ) ;
118+
119+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
120+ {
121+ // On Windows, the apphost will look next to the symlink for the app dll and find the symlinks
122+ result
123+ . Should ( ) . Pass ( )
124+ . And . HaveStdOutContaining ( "Hello World" ) ;
125+ }
126+ else
127+ {
128+ // On Unix, the apphost will not find the app files next to the symlink
129+ result
130+ . Should ( ) . Fail ( )
131+ . And . HaveStdErrContaining ( "The application to execute does not exist" ) ;
132+ }
133+ }
134+ finally
135+ {
136+ foreach ( var symlink in symlinks )
137+ {
138+ symlink . Dispose ( ) ;
139+ }
140+ }
141+ }
142+
143+ [ Theory ]
144+ [ InlineData ( "a/b/SymlinkToFrameworkDependentApp" ) ]
145+ [ InlineData ( "a/SymlinkToFrameworkDependentApp" ) ]
146+ public void Symlink_all_files_self_contained ( string symlinkRelativePath )
147+ {
148+ using var testDir = TestArtifact . Create ( "symlink" ) ;
149+ Directory . CreateDirectory ( Path . Combine ( testDir . Location , Path . GetDirectoryName ( symlinkRelativePath ) ) ) ;
150+
151+ // Symlink every file in the app directory
152+ var symlinks = new List < SymLink > ( ) ;
153+ try
154+ {
155+ foreach ( var file in Directory . EnumerateFiles ( sharedTestState . SelfContainedApp . Location ) )
156+ {
157+ var fileName = Path . GetFileName ( file ) ;
158+ var symlinkPath = Path . Combine ( testDir . Location , symlinkRelativePath , fileName ) ;
159+ Directory . CreateDirectory ( Path . GetDirectoryName ( symlinkPath ) ) ;
160+ symlinks . Add ( new SymLink ( symlinkPath , file ) ) ;
161+ }
162+
163+ var result = Command . Create ( Path . Combine ( testDir . Location , symlinkRelativePath , Path . GetFileName ( sharedTestState . FrameworkDependentApp . AppExe ) ) )
164+ . CaptureStdErr ( )
165+ . CaptureStdOut ( )
166+ . DotNetRoot ( TestContext . BuiltDotNet . BinPath )
167+ . Execute ( ) ;
168+
169+ // This should succeed on all platforms, but for different reasons:
170+ // * Windows: The apphost will look next to the symlink for the files and find the symlinks
171+ // * Unix: The apphost will look next to the resolved apphost for the files and find the real thing
172+ result
173+ . Should ( ) . Pass ( )
174+ . And . HaveStdOutContaining ( "Hello World" ) ;
175+ }
176+ finally
177+ {
178+ foreach ( var symlink in symlinks )
179+ {
180+ symlink . Dispose ( ) ;
181+ }
182+ }
183+ }
184+
24185 [ Theory ]
25186 [ InlineData ( "a/b/SymlinkToApphost" ) ]
26187 [ InlineData ( "a/SymlinkToApphost" ) ]
@@ -33,12 +194,23 @@ public void Run_apphost_behind_symlink(string symlinkRelativePath)
33194 var symlinkFullPath = Path . Combine ( testDir . Location , symlinkRelativePath ) ;
34195
35196 using var symlink = new SymLink ( symlinkFullPath , sharedTestState . SelfContainedApp . AppExe ) ;
36- Command . Create ( symlinkFullPath )
197+ var result = Command . Create ( symlinkFullPath )
37198 . CaptureStdErr ( )
38199 . CaptureStdOut ( )
39- . Execute ( )
40- . Should ( ) . Pass ( )
41- . And . HaveStdOutContaining ( "Hello World" ) ;
200+ . Execute ( ) ;
201+
202+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
203+ {
204+ result
205+ . Should ( ) . Fail ( )
206+ . And . HaveStdErrContaining ( "The application to execute does not exist" ) ;
207+ }
208+ else
209+ {
210+ result
211+ . Should ( ) . Pass ( )
212+ . And . HaveStdOutContaining ( "Hello World" ) ;
213+ }
42214 }
43215 }
44216
@@ -63,12 +235,23 @@ public void Run_apphost_behind_transitive_symlinks(string firstSymlinkRelativePa
63235 Directory . CreateDirectory ( Path . GetDirectoryName ( symlink1Path ) ) ;
64236 using var symlink1 = new SymLink ( symlink1Path , symlink2Path ) ;
65237
66- Command . Create ( symlink1 . SrcPath )
238+ var result = Command . Create ( symlink1 . SrcPath )
67239 . CaptureStdErr ( )
68240 . CaptureStdOut ( )
69- . Execute ( )
70- . Should ( ) . Pass ( )
71- . And . HaveStdOutContaining ( "Hello World" ) ;
241+ . Execute ( ) ;
242+
243+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
244+ {
245+ result
246+ . Should ( ) . Fail ( )
247+ . And . HaveStdErrContaining ( "The application to execute does not exist" ) ;
248+ }
249+ else
250+ {
251+ result
252+ . Should ( ) . Pass ( )
253+ . And . HaveStdOutContaining ( "Hello World" ) ;
254+ }
72255 }
73256 }
74257
@@ -86,13 +269,24 @@ public void Run_framework_dependent_app_behind_symlink(string symlinkRelativePat
86269 Directory . CreateDirectory ( Path . Combine ( testDir . Location , Path . GetDirectoryName ( symlinkRelativePath ) ) ) ;
87270
88271 using var symlink = new SymLink ( Path . Combine ( testDir . Location , symlinkRelativePath ) , sharedTestState . FrameworkDependentApp . AppExe ) ;
89- Command . Create ( symlink . SrcPath )
272+ var result = Command . Create ( symlink . SrcPath )
90273 . CaptureStdErr ( )
91274 . CaptureStdOut ( )
92275 . DotNetRoot ( TestContext . BuiltDotNet . BinPath )
93- . Execute ( )
94- . Should ( ) . Pass ( )
95- . And . HaveStdOutContaining ( "Hello World" ) ;
276+ . Execute ( ) ;
277+
278+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
279+ {
280+ result
281+ . Should ( ) . Fail ( )
282+ . And . HaveStdErrContaining ( "The application to execute does not exist" ) ;
283+ }
284+ else
285+ {
286+ result
287+ . Should ( ) . Pass ( )
288+ . And . HaveStdOutContaining ( "Hello World" ) ;
289+ }
96290 }
97291 }
98292
@@ -144,12 +338,23 @@ public void Put_dotnet_behind_symlink()
144338 var dotnetSymlink = Path . Combine ( testDir . Location , Binaries . DotNet . FileName ) ;
145339
146340 using var symlink = new SymLink ( dotnetSymlink , TestContext . BuiltDotNet . DotnetExecutablePath ) ;
147- Command . Create ( symlink . SrcPath , sharedTestState . SelfContainedApp . AppDll )
341+ var result = Command . Create ( symlink . SrcPath , sharedTestState . SelfContainedApp . AppDll )
148342 . CaptureStdErr ( )
149343 . CaptureStdOut ( )
150- . Execute ( )
151- . Should ( ) . Pass ( )
152- . And . HaveStdOutContaining ( "Hello World" ) ;
344+ . Execute ( ) ;
345+
346+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Windows ) )
347+ {
348+ result
349+ . Should ( ) . Fail ( )
350+ . And . HaveStdErrContaining ( $ "[{ Path . Combine ( testDir . Location , "host" , "fxr" ) } ] does not exist") ;
351+ }
352+ else
353+ {
354+ result
355+ . Should ( ) . Pass ( )
356+ . And . HaveStdOutContaining ( "Hello World" ) ;
357+ }
153358 }
154359 }
155360
0 commit comments