1+ // -----------------------------------------------------------------------------
2+ // PROJECT : PupNet
3+ // COPYRIGHT : Andy Thomas (C) 2022-23
4+ // LICENSE : GPL-3.0-or-later
5+ // HOMEPAGE : https://github.com/kuiperzone/PupNet
6+ //
7+ // PupNet is free software: you can redistribute it and/or modify it under
8+ // the terms of the GNU Affero General Public License as published by the Free Software
9+ // Foundation, either version 3 of the License, or (at your option) any later version.
10+ //
11+ // PupNet is distributed in the hope that it will be useful, but WITHOUT
12+ // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+ // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
14+ //
15+ // You should have received a copy of the GNU Affero General Public License along
16+ // with PupNet. If not, see <https://www.gnu.org/licenses/>.
17+ // -----------------------------------------------------------------------------
18+
19+ using System . Runtime . InteropServices ;
20+
21+ namespace KuiperZone . PupNet . Test ;
22+
23+ /// <summary>
24+ /// This goes a little beyond the scope of unit test, and performs an "integration test" against <see cref="BuildHost"/>.
25+ /// To do this, we must have installed all the third-party builder-tools and we will actually produce a dummy package
26+ /// output for each test. Although not ideal, it is necessary as testing for each package output kind prior to releasing
27+ /// the software is otherwise an intensive and error prone exercise. Here, we run the tests only in RELEASE builds only
28+ /// as each test execution blocks. It is recommended to run the tests with "dotnet test -c Release" ON MOST PLATFORMS
29+ /// prior to releasing a new version of pupnet. NOTE. Cannot be used with Flatpak or Windows Setup (damn!).
30+ /// </summary>
31+ public class BuildHostIntegrationTest
32+ {
33+ [ Fact ]
34+ public void BuildZip_EnsureBuildSucceedsAndOutputExists ( )
35+ {
36+ // We can always test zip
37+ Assert_BuildPackage ( PackageKind . Zip , false ) ;
38+ Assert_BuildPackage ( PackageKind . Zip , true ) ;
39+ }
40+
41+
42+ #if ! DEBUG
43+ [ Fact ]
44+ public void BuildThirdParty_EnsureBuildSucceedsAndOutputExists ( )
45+ {
46+ if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
47+ {
48+ Assert_BuildPackage ( PackageKind . AppImage , false ) ;
49+ Assert_BuildPackage ( PackageKind . AppImage , true ) ;
50+
51+ Assert_BuildPackage ( PackageKind . Deb , false ) ;
52+ Assert_BuildPackage ( PackageKind . Deb , true ) ;
53+
54+ Assert_BuildPackage ( PackageKind . Rpm , false ) ;
55+ Assert_BuildPackage ( PackageKind . Rpm , true ) ;
56+ }
57+ }
58+ #endif
59+
60+ private void Assert_BuildPackage ( PackageKind kind , bool complete , bool assertOutput = true )
61+ {
62+ string ? metadata = null ;
63+ string ? manifest = null ;
64+ var conf = new TestConfiguration ( kind , complete ) ;
65+
66+ try
67+ {
68+ var host = new BuildHost ( conf ) ;
69+
70+ // Must create build outside of BuildHost.Run()
71+ host . Builder . Create ( host . ExpandedDesktop , host . ExpandedMetaInfo ) ;
72+ metadata = host . ExpandedMetaInfo ;
73+ manifest = host . Builder . ManifestContent ;
74+
75+ // Regression test - test for correct icon
76+ if ( host . Builder . IsLinuxExclusive )
77+ {
78+ // If we do not define icon (i.e complete == false),
79+ // we still get default icon on Linux
80+ Assert . NotNull ( host . Builder . PrimaryIcon ) ;
81+
82+ if ( complete )
83+ {
84+ // Icon provided in config below
85+ // Always chooses SVG if one is provided over PNG
86+ Assert . EndsWith ( "Icon.svg" , host . Builder . PrimaryIcon ) ;
87+ }
88+ else
89+ {
90+ // Default icon is built into application.
91+ // We have set DesktopTerminal to true below, so expect "terminal" icon
92+ // We will accept either SVG or max size PNG
93+ bool hasSvg = host . Builder . PrimaryIcon . Contains ( "terminal.svg" ) ; ;
94+ bool hasPng = host . Builder . PrimaryIcon . Contains ( "terminal.256x256" ) ;
95+ Assert . True ( hasSvg || hasPng ) ;
96+ }
97+ }
98+
99+ if ( host . Builder . IsOsxExclusive )
100+ {
101+ // Test here
102+ }
103+
104+ if ( host . Builder . IsWindowsExclusive )
105+ {
106+ // Windows? We are not declaring Windows icon currently - must be null
107+ Assert . Null ( host . Builder . PrimaryIcon ) ;
108+ }
109+
110+
111+ // We do NOT call dotnet publish, and must create dummy app file, otherwise build will fail.
112+ var appPath = Path . Combine ( host . Builder . BuildAppBin , host . Builder . AppExecName ) ;
113+ File . WriteAllText ( appPath , "Dummy app binary" ) ;
114+
115+ host . Builder . BuildPackage ( ) ;
116+
117+ if ( assertOutput )
118+ {
119+ // Check both file and directory (RPM output a directory)
120+ Assert . True ( File . Exists ( host . Builder . OutputPath ) || Directory . Exists ( host . Builder . OutputPath ) ) ;
121+ }
122+ }
123+ catch ( Exception e )
124+ {
125+ Console . WriteLine ( "==============================" ) ;
126+ Console . WriteLine ( $ "BUILD FAILED: { kind } , { complete } ") ;
127+ Console . WriteLine ( "==============================" ) ;
128+ Console . WriteLine ( e ) ;
129+ Console . WriteLine ( ) ;
130+
131+ // For debug if fails
132+ Console . WriteLine ( "==============================" ) ;
133+ Console . WriteLine ( $ "CONFIGURATION: { kind } , { complete } ") ;
134+ Console . WriteLine ( "==============================" ) ;
135+ Console . WriteLine ( conf . ToString ( ) ) ;
136+ Console . WriteLine ( ) ;
137+
138+ Console . WriteLine ( "==============================" ) ;
139+ Console . WriteLine ( $ "METADATA: { kind } , { complete } ") ;
140+ Console . WriteLine ( "==============================" ) ;
141+ Console . WriteLine ( metadata ?? "[NONE]" ) ;
142+ Console . WriteLine ( ) ;
143+
144+ Console . WriteLine ( "==============================" ) ;
145+ Console . WriteLine ( $ "MANIFEST: { kind } , { complete } ") ;
146+ Console . WriteLine ( "==============================" ) ;
147+ Console . WriteLine ( manifest ?? "[NONE]" ) ;
148+
149+ throw ;
150+ }
151+ finally
152+ {
153+ Directory . Delete ( conf . OutputDirectory , true ) ;
154+ }
155+ }
156+
157+ private class TestConfiguration : ConfigurationReader
158+ {
159+ public TestConfiguration ( PackageKind kind , bool complete )
160+ : base ( new ArgumentReader ( $ "-k { kind } -y --verbose") , Create ( complete ) )
161+ {
162+ // NB. We need to skip prompt above
163+ }
164+
165+ private static string [ ] Create ( bool complete )
166+ {
167+ // Use unique temporary directory for everything
168+ var workDir = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( ) ) ;
169+ Directory . CreateDirectory ( workDir ) ;
170+
171+ var lines = new List < string > ( ) ;
172+
173+ // The idea here is to include only the minimal set of configuration we expect to build successfully
174+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppBaseName ) } = 'HelloWorld'") ;
175+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppFriendlyName ) } = Hello World") ;
176+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppId ) } = \" net.example.helloworld\" ") ;
177+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppVersionRelease ) } = 5.4.3[2]") ;
178+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppShortSummary ) } = Test <application> only") ;
179+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppLicenseId ) } = LicenseRef-LICENSE") ;
180+
181+ lines . Add ( $ "{ nameof ( ConfigurationReader . PublisherName ) } = Kuiper Zone") ;
182+ lines . Add ( $ "{ nameof ( ConfigurationReader . PublisherLinkUrl ) } = https://kuiper.zone") ;
183+ lines . Add ( $ "{ nameof ( ConfigurationReader . PublisherEmail ) } = [email protected] ") ; 184+
185+ lines . Add ( $ "{ nameof ( ConfigurationReader . DesktopTerminal ) } = true") ;
186+
187+ lines . Add ( $ "{ nameof ( ConfigurationReader . OutputDirectory ) } = { workDir } ") ;
188+
189+ // IMPORTANT - SDK must be installed
190+ lines . Add ( $ "{ nameof ( ConfigurationReader . FlatpakPlatformRuntime ) } = org.freedesktop.Platform") ;
191+ lines . Add ( $ "{ nameof ( ConfigurationReader . FlatpakPlatformSdk ) } = org.freedesktop.Sdk") ;
192+ lines . Add ( $ "{ nameof ( ConfigurationReader . FlatpakPlatformVersion ) } = \" 22.00\" ") ;
193+ lines . Add ( $ "{ nameof ( ConfigurationReader . SetupMinWindowsVersion ) } = 10") ;
194+
195+ // Always include metafile We actually need to create the file here
196+ var metapath = Path . Combine ( workDir , "app.metainfo.xml" ) ;
197+ File . WriteAllText ( metapath , MetaTemplates . MetaInfo ) ;
198+ lines . Add ( $ "{ nameof ( ConfigurationReader . MetaFile ) } = { metapath } ") ;
199+
200+ if ( complete )
201+ {
202+ // Here we add extended configuration we consider optional extras
203+ lines . Add ( $ "{ nameof ( ConfigurationReader . PackageName ) } = HelloWorld") ;
204+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppDescription ) } = Test description\n \n * bullet1\n - bullet2\n Line2") ;
205+ lines . Add ( $ "{ nameof ( ConfigurationReader . PublisherCopyright ) } = Copyright Kuiper Zone") ;
206+ lines . Add ( $ "{ nameof ( ConfigurationReader . PublisherLinkName ) } = kuiper.zone") ;
207+
208+ lines . Add ( $ "{ nameof ( ConfigurationReader . DesktopNoDisplay ) } = false") ;
209+ lines . Add ( $ "{ nameof ( ConfigurationReader . PrimeCategory ) } = Development") ;
210+ lines . Add ( $ "{ nameof ( ConfigurationReader . AppImageVersionOutput ) } = true") ;
211+ lines . Add ( $ "{ nameof ( ConfigurationReader . FlatpakFinishArgs ) } = --socket=wayland;--socket=fallback-x11;--filesystem=host;--share=network") ;
212+
213+ lines . Add ( $ "{ nameof ( ConfigurationReader . RpmAutoReq ) } = true") ;
214+ lines . Add ( $ "{ nameof ( ConfigurationReader . RpmAutoProv ) } = false") ;
215+
216+ lines . Add ( $ "{ nameof ( ConfigurationReader . SetupVersionOutput ) } = true") ;
217+ lines . Add ( $ "{ nameof ( ConfigurationReader . SetupCommandPrompt ) } = Command Prompt") ;
218+
219+ // Need to create dummy icons in order to get the thing to build (we cheat with dummy files).
220+ // However, we can't write dummy ico for windows because Setup would fail (needs to be valid icon)
221+ var icons = new List < string > ( ) ;
222+ icons . Add ( Path . Combine ( workDir , "Icon.32.png" ) ) ;
223+ File . WriteAllText ( icons [ ^ 1 ] , "Dummy file" ) ;
224+
225+ icons . Add ( Path . Combine ( workDir , "Icon.64.png" ) ) ;
226+ File . WriteAllText ( icons [ ^ 1 ] , "Dummy file" ) ;
227+
228+ icons . Add ( Path . Combine ( workDir , "Icon.svg" ) ) ;
229+ File . WriteAllText ( icons [ ^ 1 ] , "Dummy file" ) ;
230+
231+ lines . Add ( $ "{ nameof ( ConfigurationReader . IconFiles ) } = { string . Join ( ';' , icons ) } ") ;
232+ }
233+
234+ return lines . ToArray ( ) ;
235+ }
236+ }
237+ }
0 commit comments