-
Notifications
You must be signed in to change notification settings - Fork 525
/
Copy pathTestHelper.fs
361 lines (300 loc) · 13.2 KB
/
TestHelper.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
[<AutoOpen>]
module Paket.IntegrationTests.TestHelpers
open Fake
open Paket
open System
open NUnit.Framework
open FsUnit
open System
open System.IO
open Paket.Logging
let disableScenarioCleanup = false // change to true to debug a single test temporarily.
let isLiveUnitTesting = AppDomain.CurrentDomain.GetAssemblies() |> Seq.exists (fun a -> a.GetName().Name = "Microsoft.CodeAnalysis.LiveUnitTesting.Runtime")
let dotnetToolPath =
match Environment.GetEnvironmentVariable "DOTNET_EXE_PATH" with
| null | "" -> "dotnet"
| s -> s
let paketToolPath =
#if PAKET_NETCORE
dotnetToolPath, FullName(__SOURCE_DIRECTORY__ + "../../../bin/netcoreapp3.1/paket.dll")
#else
"", FullName(__SOURCE_DIRECTORY__ + "../../../bin/net461/paket.exe")
#endif
let paketBootstrapperToolPath =
#if PAKET_NETCORE
dotnetToolPath, FullName(__SOURCE_DIRECTORY__ + "../../../bin_bootstrapper/netcoreapp3.1/paket.bootstrapper.dll")
#else
"", FullName(__SOURCE_DIRECTORY__ + "../../../bin_bootstrapper/net461/paket.bootstrapper.exe")
#endif
let integrationTestPath = FullName(__SOURCE_DIRECTORY__ + "../../../integrationtests/scenarios")
let scenarioTempPath scenario = Path.Combine(integrationTestPath,scenario,"temp")
let originalScenarioPath scenario = Path.Combine(integrationTestPath,scenario,"before")
let cleanup scenario =
let scenarioPath = scenarioTempPath scenario
try
CleanDir scenarioPath
with e ->
traceWarnfn "Failed to clean dir '%s', trying again: %O" scenarioPath e
CleanDir scenarioPath
//let cleanupAllScenarios() =
// for scenario in scenarios |> Seq.toList do
// try
// cleanup scenario
// scenarios.Remove(scenario) |> ignore<bool>
// with e ->
// traceWarnfn "Failed to cleanup a particular scenario %s, %O" scenario e
let createScenarioDir scenario =
let scenarioPath = scenarioTempPath scenario
CleanDir scenarioPath
scenarioPath
let prepare scenario =
if isLiveUnitTesting then Assert.Inconclusive("Integration tests are disabled when in a Live-Unit-Session")
//if scenarios.Count > 10 then
// cleanupAllScenarios()
//scenarios.Add scenario
let cleanup =
{ new System.IDisposable with
member x.Dispose() =
if not disableScenarioCleanup then
try
cleanup scenario
with e -> eprintfn "Error in test cleanup (Dispose): %O" e }
let mutable shouldDispose = cleanup
try
let originalScenarioPath = originalScenarioPath scenario
let scenarioPath = createScenarioDir scenario
CopyDir scenarioPath originalScenarioPath (fun _ -> true)
for ext in ["fsproj";"csproj";"vcxproj";"template";"json"] do
for file in Directory.GetFiles(scenarioPath, (sprintf "*.%stemplate" ext), SearchOption.AllDirectories) do
File.Move(file, Path.ChangeExtension(file, ext))
shouldDispose <- null
cleanup
finally
if not (isNull shouldDispose) then shouldDispose.Dispose()
let prepareSdk scenario =
let tmpPaketFolder = (scenarioTempPath scenario) @@ ".paket"
let targetsFile = FullName(__SOURCE_DIRECTORY__ + "../../../src/Paket.Core/embedded/Paket.Restore.targets")
let paketExe = snd paketToolPath
setEnvironVar "PaketExePath" paketExe
let cleanup = prepare scenario
if (not (Directory.Exists tmpPaketFolder)) then
Directory.CreateDirectory tmpPaketFolder |> ignore
FileHelper.CopyFile tmpPaketFolder targetsFile
cleanup
type OutputMsg =
{ IsError : bool; Message : string }
static member isError ({ IsError = e}:OutputMsg) = e
static member getMessage ({ Message = msg }:OutputMsg) = msg
type OutputData =
internal { _Messages : ResizeArray<OutputMsg> }
member x.Messages : seq<OutputMsg> = x._Messages :> _
member x.Errors = x._Messages |> Seq.filter OutputMsg.isError |> Seq.map OutputMsg.getMessage
member x.Outputs = x._Messages |> Seq.filter (not << OutputMsg.isError) |> Seq.map OutputMsg.getMessage
exception ProcessFailedWithExitCode of exitCode:int * fileName:string * msgs:OutputData
with
override x.Message =
let output = String.Join(Environment.NewLine,x.msgs.Messages |> Seq.map (fun m -> (if m.IsError then "ERR:" else "OUT:") + m.Message ))
sprintf "The process '%s' exited with code %i, output: \n%s" x.fileName x.exitCode output
let directToolEx env isPaket toolInfo commands workingDir =
let processFilename, processArgs =
match fst toolInfo, snd toolInfo with
| "", path ->
path, commands
| host, path ->
host, (sprintf "%s %s" path commands)
#if INTERACTIVE
let result =
ExecProcessWithLambdas (fun info ->
info.FileName <- processFilename
info.WorkingDirectory <- workingDir
info.Arguments <- processArgs)
(System.TimeSpan.FromMinutes 7.)
false
(printfn "%s")
(printfn "%s")
let res = new ResizeArray()
res.Add (string result)
res
#else
Environment.SetEnvironmentVariable("PAKET_DETAILED_ERRORS", "true")
Environment.SetEnvironmentVariable("PAKET_DETAILED_WARNINGS", "true")
printfn "%s> %s %s" workingDir (if isPaket then "paket" else processFilename) processArgs
let perfMessages = ResizeArray()
let msgs = ResizeArray<OutputMsg>()
let mutable perfMessagesStarted = false
let addAndPrint isError msg =
if not isError then
if isPaket && msg = "Performance:" then
perfMessagesStarted <- true
elif isPaket && perfMessagesStarted then
perfMessages.Add(msg)
msgs.Add({ IsError = isError; Message = msg})
let result =
try
ExecProcessWithLambdas (fun info ->
info.FileName <- processFilename
for key, value in env do
info.EnvironmentVariables.[key] <- value
info.WorkingDirectory <- workingDir
info.CreateNoWindow <- true
info.Arguments <- processArgs)
(System.TimeSpan.FromMinutes 7.)
true
(addAndPrint true)
(addAndPrint false)
with exn ->
if exn.Message.Contains "timed out" then
printfn "PROCESS TIMED OUT, OUTPUT WAS: "
else
printfn "ExecProcessWithLambdas failed. Output was: "
for { IsError = isError; Message = msg } in msgs do
printfn "%s%s" (if isError then "ERR: " else "") msg
reraise()
// always print stderr
for msg in msgs do
if msg.IsError then
printfn "ERR: %s" msg.Message
if isPaket then
// Only throw after the result <> 0 check because the current test might check the argument parsing
// this is the only case where no performance is printed
let isUsageError = result <> 0 && msgs |> Seq.filter OutputMsg.isError |> Seq.map OutputMsg.getMessage |> Seq.exists (fun msg -> msg.Contains "USAGE:")
if not isUsageError then
printfn "Performance:"
for msg in perfMessages do
printfn "%s" msg
if result <> 0 then
raise <| ProcessFailedWithExitCode(result, processFilename, { _Messages = msgs })
msgs
#endif
let directPaketInPathEx command scenarioPath =
directToolEx [] true paketToolPath command scenarioPath
let directPaketInPathExWithEnv command scenarioPath env =
directToolEx env true paketToolPath command scenarioPath
let checkResults msgs =
msgs
|> Seq.filter OutputMsg.isError
|> Seq.toList
|> shouldEqual []
let directDotnetEx env checkZeroWarn command workingDir =
let msgs = directToolEx env false ("", dotnetToolPath) command workingDir
if checkZeroWarn then checkResults msgs
msgs
let directDotnet checkZeroWarn command workingDir =
directDotnetEx [] checkZeroWarn command workingDir
let private fromMessages msgs =
String.Join(Environment.NewLine,msgs |> Seq.map OutputMsg.getMessage)
let directPaketInPath command scenarioPath = directPaketInPathEx command scenarioPath |> fromMessages
let directPaketEx command scenario =
directPaketInPathEx command (scenarioTempPath scenario)
let directPaket command scenario = directPaketEx command scenario |> fromMessages
let paketEx checkZeroWarn command scenario =
let cleanup = prepare scenario
let mutable shouldDispose = cleanup
try
let msgs = directPaketEx command scenario
if checkZeroWarn then checkResults msgs
shouldDispose <- null
cleanup, msgs
finally
if not (isNull shouldDispose) then shouldDispose.Dispose()
let paket command scenario =
let mutable shouldDispose = null
try
let cleanup, msgs = paketEx false command scenario
shouldDispose <- cleanup
let newMsgs = msgs |> fromMessages
shouldDispose <- null
cleanup, newMsgs
finally
if not (isNull shouldDispose) then shouldDispose.Dispose()
let updateEx checkZeroWarn scenario =
let mutable shouldDispose = null
try
let cleanup = paketEx checkZeroWarn "update" scenario |> fst
shouldDispose <- cleanup
let lockFile = LockFile.LoadFrom(Path.Combine(scenarioTempPath scenario,"paket.lock"))
shouldDispose <- null
cleanup, lockFile
finally
if not (isNull shouldDispose) then shouldDispose.Dispose()
let update scenario =
updateEx false scenario
let installEx checkZeroWarn scenario =
#if INTERACTIVE
paket "install --verbose" scenario |> printfn "%s"
#else
paketEx checkZeroWarn "install" scenario |> fst,
#endif
LockFile.LoadFrom(Path.Combine(scenarioTempPath scenario,"paket.lock"))
let install scenario = installEx false scenario
let restore scenario = paketEx false "restore" scenario |> fst
let updateShouldFindPackageConflict packageName scenario =
try
use __ = update scenario |> fst
failwith "No conflict was found."
with
| exn when exn.Message.Contains("Conflict detected") && exn.Message.Contains(sprintf "requested package %s" packageName) ->
#if INTERACTIVE
printfn "Ninject conflict test passed"
#endif
()
let clearPackage name =
// ~/.nuget/packages
let userPackageFolder = Paket.Constants.UserNuGetPackagesFolder
// %APPDATA%/NuGet/Cache
let nugetCache = Paket.Constants.NuGetCacheFolder
for cacheDir in [ nugetCache; userPackageFolder ] do
if Directory.Exists cacheDir then
Directory.EnumerateDirectories(cacheDir)
|> Seq.filter (fun n -> Path.GetFileName n |> String.startsWithIgnoreCase name)
|> Seq.iter (fun n -> Directory.Delete(n, true))
Directory.EnumerateFiles(cacheDir)
|> Seq.filter (fun n -> Path.GetFileName n |> String.startsWithIgnoreCase name)
|> Seq.iter (fun n -> File.Delete(n))
let isPackageCached name version =
// ~/.nuget/packages
let userPackageFolder = Paket.Constants.UserNuGetPackagesFolder
// %APPDATA%/NuGet/Cache
let nugetCache = Paket.Constants.NuGetCacheFolder
[ for cacheDir in [ nugetCache; userPackageFolder ] do
if Directory.Exists cacheDir then
yield!
Directory.EnumerateDirectories(cacheDir)
|> Seq.filter (fun n -> Path.GetFileName n |> String.equalsIgnoreCase name)
|> Seq.collect (fun n -> Directory.EnumerateDirectories(n))
|> Seq.filter (fun n -> Path.GetFileName n |> String.equalsIgnoreCase version)
|> Seq.toList ]
let clearPackageAtVersion name version =
isPackageCached name version
|> List.iter (fun n -> Directory.Delete(n, true))
// Checks if a given package is present in cache ONLY with lowercase naming (see issue #2812)
let isPackageCachedWithOnlyLowercaseNames (name: string) =
// // ~/.nuget/packages
let userPackageFolder = Paket.Constants.UserNuGetPackagesFolder
// // %APPDATA%/NuGet/Cache
let nugetCache = Paket.Constants.NuGetCacheFolder
let lowercaseName = name.ToLowerInvariant()
let packageFolders =
[ nugetCache; userPackageFolder ]
|> List.collect (Directory.GetDirectories >> List.ofArray)
|> List.filter (fun x -> Path.GetFileName x |> String.equalsIgnoreCase name)
let packageFolderNames = packageFolders |> List.map Path.GetFileName |> List.distinct
// ensure that names of package directories are lowercase only
match packageFolderNames with
| [ x ] when x = lowercaseName ->
// ensure thet names o package files that start with package name are lowercase only
let packageFiles =
packageFolders
|> Seq.collect Directory.GetDirectories
|> Seq.collect Directory.GetFiles
let packageFileNames = packageFiles |> Seq.map Path.GetFileName
let packageNameSegments =
packageFileNames
|> Seq.filter (String.startsWithIgnoreCase <| sprintf "%s." name)
|> Seq.map (fun x -> x.Substring(0, name.Length))
|> Seq.distinct
|> List.ofSeq
packageNameSegments = [ lowercaseName ]
| _ -> false
[<AttributeUsage(AttributeTargets.Method, AllowMultiple=false)>]
type FlakyAttribute() = inherit CategoryAttribute()