@@ -9,7 +9,7 @@ open FSharp.Data.HttpRequestHeaders
99open Microsoft.AspNetCore .Builder
1010open Microsoft.AspNetCore .Http
1111open System.Threading .Tasks
12- open System.Net .NetworkInformation
12+ open System.Net .Sockets
1313open System.IO
1414open System.Text
1515
@@ -50,29 +50,31 @@ let startXmlHttpLocalServer() =
5050 } |> Async.StartAsTask :> Task
5151 )) |> ignore
5252
53+ // Use TcpListener(0) to ask the OS for a free port, then release it.
54+ // This avoids Windows excluded port ranges (reserved by Hyper-V/Docker) that
55+ // caused intermittent SocketException (10013: WSAEACCES) on Windows CI.
5356 let freePort =
54- let random = new System.Random()
55- let mutable port = random.Next( 10000 , 65000 )
56- while
57- IPGlobalProperties.GetIPGlobalProperties() .GetActiveTcpListeners()
58- |> Array.map ( fun x -> x.Port)
59- |> Array.contains port do
60- port <- random.Next( 10000 , 65000 )
57+ let listener = new TcpListener( System.Net.IPAddress.Loopback, 0 )
58+ listener.Start()
59+ let port = ( listener.LocalEndpoint :?> System.Net.IPEndPoint) .Port
60+ listener.Stop()
6161 port
6262
6363 let baseAddress = $" http://127.0.0.1:{freePort}"
64- let workerTask = app.RunAsync( baseAddress)
64+
65+ // Use StartAsync so the server is guaranteed ready before we return
66+ app.Urls.Add( baseAddress)
67+ app.StartAsync() |> Async.AwaitTask |> Async.RunSynchronously
6568
6669 { new ITestHttpServer with
67- member this .Dispose() =
68- app.StopAsync() |> Async.AwaitTask |> ignore
69- member this .WorkerTask = workerTask
70- member this .BaseAddress = baseAddress }
70+ member _ .Dispose() =
71+ app.StopAsync() |> Async.AwaitTask |> Async.RunSynchronously
72+ member _ .WorkerTask = Task.CompletedTask
73+ member _ .BaseAddress = baseAddress }
7174
7275[<Test>]
7376let ``XElement.Request sends XML via POST by default`` () =
7477 use localServer = startXmlHttpLocalServer()
75- System.Threading.Thread.Sleep( 100 ) // Let server start
7678
7779 let xml = XElement( XName.Get( " test" ), " sample content" )
7880 let response = xml.Request( localServer.BaseAddress + " /echo" )
@@ -85,7 +87,6 @@ let ``XElement.Request sends XML via POST by default`` () =
8587[<Test>]
8688let ``XElement.Request with custom HTTP method`` () =
8789 use localServer = startXmlHttpLocalServer()
88- System.Threading.Thread.Sleep( 100 )
8990
9091 let xml = XElement( XName.Get( " test" ), " content" )
9192 let response = xml.Request( localServer.BaseAddress + " /test/PUT" , httpMethod = HttpMethod.Put)
@@ -98,7 +99,6 @@ let ``XElement.Request with custom HTTP method`` () =
9899[<Test>]
99100let ``XElement.Request includes default User - Agent header`` () =
100101 use localServer = startXmlHttpLocalServer()
101- System.Threading.Thread.Sleep( 100 )
102102
103103 let xml = XElement( XName.Get( " test" ))
104104 let response = xml.Request( localServer.BaseAddress + " /echo" )
@@ -109,7 +109,6 @@ let ``XElement.Request includes default User-Agent header`` () =
109109[<Test>]
110110let ``XElement.Request with custom headers`` () =
111111 use localServer = startXmlHttpLocalServer()
112- System.Threading.Thread.Sleep( 100 )
113112
114113 let xml = XElement( XName.Get( " test" ))
115114 let customHeaders = [( " X-Custom-Header" , " test-value" )]
@@ -120,7 +119,6 @@ let ``XElement.Request with custom headers`` () =
120119[<Test>]
121120let ``XElement.Request preserves existing User - Agent when provided`` () =
122121 use localServer = startXmlHttpLocalServer()
123- System.Threading.Thread.Sleep( 100 )
124122
125123 let xml = XElement( XName.Get( " test" ))
126124 let customHeaders = [ UserAgent " CustomAgent/1.0" ]
@@ -131,7 +129,6 @@ let ``XElement.Request preserves existing User-Agent when provided`` () =
131129[<Test>]
132130let ``XElement.Request includes XML content type header`` () =
133131 use localServer = startXmlHttpLocalServer()
134- System.Threading.Thread.Sleep( 100 )
135132
136133 let xml = XElement( XName.Get( " test" ))
137134 let response = xml.Request( localServer.BaseAddress + " /echo" )
@@ -142,7 +139,6 @@ let ``XElement.Request includes XML content type header`` () =
142139[<Test>]
143140let ``XElement.Request with complex XML structure`` () =
144141 use localServer = startXmlHttpLocalServer()
145- System.Threading.Thread.Sleep( 100 )
146142
147143 let xml =
148144 XElement( XName.Get( " root" ),
@@ -163,7 +159,6 @@ let ``XElement.Request with complex XML structure`` () =
163159[<Test>]
164160let ``XElement.RequestAsync sends XML via POST by default`` () =
165161 use localServer = startXmlHttpLocalServer()
166- System.Threading.Thread.Sleep( 100 )
167162
168163 let xml = XElement( XName.Get( " test" ), " async content" )
169164 let response = xml.RequestAsync( localServer.BaseAddress + " /echo" ) |> Async.RunSynchronously
@@ -176,7 +171,6 @@ let ``XElement.RequestAsync sends XML via POST by default`` () =
176171// [<Test>]
177172// let ``XElement.RequestAsync with custom HTTP method`` () =
178173// use localServer = startXmlHttpLocalServer()
179- // System.Threading.Thread.Sleep(100)
180174
181175// let xml = XElement(XName.Get("test"))
182176// let response = xml.RequestAsync(localServer.BaseAddress + "/test/PUT", httpMethod = HttpMethod.Put) |> Async.RunSynchronously
@@ -189,7 +183,6 @@ let ``XElement.RequestAsync sends XML via POST by default`` () =
189183[<Test>]
190184let ``XElement.RequestAsync with custom headers`` () =
191185 use localServer = startXmlHttpLocalServer()
192- System.Threading.Thread.Sleep( 100 )
193186
194187 let xml = XElement( XName.Get( " test" ))
195188 let customHeaders = [( " X-Async-Header" , " async-value" )]
@@ -200,7 +193,6 @@ let ``XElement.RequestAsync with custom headers`` () =
200193[<Test>]
201194let ``XElement.RequestAsync includes default User - Agent header`` () =
202195 use localServer = startXmlHttpLocalServer()
203- System.Threading.Thread.Sleep( 100 )
204196
205197 let xml = XElement( XName.Get( " test" ))
206198 let response = xml.RequestAsync( localServer.BaseAddress + " /echo" ) |> Async.RunSynchronously
@@ -210,7 +202,6 @@ let ``XElement.RequestAsync includes default User-Agent header`` () =
210202[<Test>]
211203let ``XElement.RequestAsync preserves existing User - Agent when provided`` () =
212204 use localServer = startXmlHttpLocalServer()
213- System.Threading.Thread.Sleep( 100 )
214205
215206 let xml = XElement( XName.Get( " test" ))
216207 let customHeaders = [ UserAgent " AsyncAgent/1.0" ]
@@ -221,7 +212,6 @@ let ``XElement.RequestAsync preserves existing User-Agent when provided`` () =
221212[<Test>]
222213let ``XElement with namespaces serializes correctly`` () =
223214 use localServer = startXmlHttpLocalServer()
224- System.Threading.Thread.Sleep( 100 )
225215
226216 let ns = XNamespace.Get( " http://example.com/test" )
227217 let xml = XElement( ns + " root" , XAttribute( XNamespace.Xmlns + " test" , ns.NamespaceName), " content" )
@@ -235,7 +225,6 @@ let ``XElement with namespaces serializes correctly`` () =
235225[<Test>]
236226let ``XElement serialization disables formatting`` () =
237227 use localServer = startXmlHttpLocalServer()
238- System.Threading.Thread.Sleep( 100 )
239228
240229 let xml =
241230 XElement( XName.Get( " root" ),
0 commit comments