Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

260 Zeilen
9.6KB

  1. <?xml version="1.0"?>
  2. <?component error="true" debug="false"?>
  3. <component>
  4. <registration
  5. description="WscMvc SelfTestController"
  6. progid="WscMvc.SelfTestController"
  7. version="1.00"
  8. classid="{D2634944-4646-4C55-956E-4C05E7E10904}">
  9. </registration>
  10. <public>
  11. <method name="RunSelfTest">
  12. <parameter name="logDir"/>
  13. <parameter name="dbConnectionString"/>
  14. <parameter name="body"/>
  15. </method>
  16. </public>
  17. <script language="VBScript">
  18. <![CDATA[
  19. Option Explicit
  20. ' HTTP+JSON test harness, callable as GET /self-test from any CLI (curl,
  21. ' Invoke-WebRequest, etc.) - no cscript/PowerShell/WSH access to the VM
  22. ' required. Runs the same checks as tests/Test-Components.vbs, in-process,
  23. ' against the live registered components. Intentionally returns raw
  24. ' Err.Description in failure details: unlike Default.asp's own error
  25. ' handling (which must never leak internals to an arbitrary client), this
  26. ' route IS the diagnostics surface, so its whole job is to say what broke.
  27. ' This is a dev/test-milestone tool, not a production data endpoint -
  28. ' revisit whether it should be gated/removed during M6 hardening.
  29. Sub RunSelfTest(logDir, dbConnectionString, body)
  30. Dim checks, allPass
  31. checks = ""
  32. allPass = True
  33. ' --- RequestContext basic contract ---
  34. Dim ctx1, ctx1Ok, ctx1Detail
  35. ctx1Ok = False
  36. ctx1Detail = ""
  37. On Error Resume Next
  38. Set ctx1 = CreateObject("WscMvc.RequestContext")
  39. If Err.Number = 0 Then ctx1.Initialize "/self-test-a", "GET", logDir
  40. If Err.Number <> 0 Then
  41. ctx1Detail = Err.Description
  42. Err.Clear
  43. ElseIf ctx1.Path <> "/self-test-a" Then
  44. ctx1Detail = "Path roundtrip mismatch: got [" & ctx1.Path & "]"
  45. ElseIf ctx1.HttpMethod <> "GET" Then
  46. ctx1Detail = "HttpMethod roundtrip mismatch: got [" & ctx1.HttpMethod & "]"
  47. ElseIf Len(ctx1.CorrelationId) = 0 Then
  48. ctx1Detail = "CorrelationId was empty"
  49. ElseIf ctx1.ElapsedMs() < 0 Then
  50. ctx1Detail = "ElapsedMs was negative"
  51. Else
  52. ctx1Ok = True
  53. End If
  54. On Error Goto 0
  55. checks = AppendCheck(checks, "request_context_contract", ctx1Ok, ctx1Detail)
  56. allPass = allPass And ctx1Ok
  57. ' --- Two contexts must not collide on correlation id ---
  58. Dim ctx2, distinctOk, distinctDetail
  59. distinctOk = False
  60. distinctDetail = ""
  61. On Error Resume Next
  62. Set ctx2 = CreateObject("WscMvc.RequestContext")
  63. ctx2.Initialize "/self-test-b", "GET", logDir
  64. If Err.Number <> 0 Then
  65. distinctDetail = Err.Description
  66. Err.Clear
  67. ElseIf ctx1.CorrelationId = ctx2.CorrelationId Then
  68. distinctDetail = "Both contexts produced the same CorrelationId: " & ctx1.CorrelationId
  69. Else
  70. distinctOk = True
  71. End If
  72. On Error Goto 0
  73. checks = AppendCheck(checks, "correlation_id_uniqueness", distinctOk, distinctDetail)
  74. allPass = allPass And distinctOk
  75. ' --- Shared Application must isolate route sets. The test app must not
  76. ' activate or test production's HomeController. ---
  77. Dim app, ctxUnknown, unkStatus, unkType, unkBody, unkAllow, unkOk, unkDetail
  78. unkOk = False
  79. unkDetail = ""
  80. On Error Resume Next
  81. Set app = CreateObject("WscMvc.Application")
  82. Set ctxUnknown = CreateObject("WscMvc.RequestContext")
  83. ctxUnknown.Initialize "/hello", "GET", logDir
  84. unkStatus = "" : unkType = "" : unkBody = "" : unkAllow = ""
  85. app.Run ctxUnknown, "tests", "", "", unkStatus, unkType, unkBody, unkAllow
  86. If Err.Number <> 0 Then
  87. unkDetail = Err.Description
  88. Err.Clear
  89. ElseIf unkStatus <> "404 Not Found" Then
  90. unkDetail = "Expected 404 Not Found, got [" & unkStatus & "]"
  91. Else
  92. unkOk = True
  93. End If
  94. On Error Goto 0
  95. checks = AppendCheck(checks, "test_app_rejects_production_route", unkOk, unkDetail)
  96. allPass = allPass And unkOk
  97. ' --- Method dispatch contract: test app self-test route supports both
  98. ' GET and POST, and reports an Allow header for unsupported methods. ---
  99. Dim router, ctxPost, postStatus, postType, postBody, postAllow, postHandler, postOk, postDetail
  100. postOk = False
  101. postDetail = ""
  102. On Error Resume Next
  103. Set router = CreateObject("WscMvc.Router")
  104. Set ctxPost = CreateObject("WscMvc.RequestContext")
  105. ctxPost.Initialize "/self-test", "POST", logDir
  106. postStatus = "" : postType = "" : postBody = "" : postAllow = "" : postHandler = ""
  107. router.Match ctxPost, "tests", postStatus, postType, postBody, postAllow, postHandler
  108. If Err.Number <> 0 Then
  109. postDetail = Err.Description
  110. Err.Clear
  111. ElseIf postHandler <> "SelfTest.RunSelfTest" Then
  112. postDetail = "Expected SelfTest.RunSelfTest handler, got [" & postHandler & "]"
  113. ElseIf postStatus <> "" Then
  114. postDetail = "Expected empty status for matched route, got [" & postStatus & "]"
  115. Else
  116. postOk = True
  117. End If
  118. On Error Goto 0
  119. checks = AppendCheck(checks, "post_self_test_route", postOk, postDetail)
  120. allPass = allPass And postOk
  121. Dim ctxDelete, delStatus, delType, delBody, delAllow, delHandler, delOk, delDetail
  122. delOk = False
  123. delDetail = ""
  124. On Error Resume Next
  125. Set ctxDelete = CreateObject("WscMvc.RequestContext")
  126. ctxDelete.Initialize "/self-test", "DELETE", logDir
  127. delStatus = "" : delType = "" : delBody = "" : delAllow = "" : delHandler = ""
  128. router.Match ctxDelete, "tests", delStatus, delType, delBody, delAllow, delHandler
  129. If Err.Number <> 0 Then
  130. delDetail = Err.Description
  131. Err.Clear
  132. ElseIf delStatus <> "405 Method Not Allowed" Then
  133. delDetail = "Expected 405 Method Not Allowed, got [" & delStatus & "]"
  134. ElseIf delAllow <> "GET, POST" Then
  135. delDetail = "Expected Allow [GET, POST], got [" & delAllow & "]"
  136. Else
  137. delOk = True
  138. End If
  139. On Error Goto 0
  140. checks = AppendCheck(checks, "delete_self_test_allow_header", delOk, delDetail)
  141. allPass = allPass And delOk
  142. ' --- Database connectivity under the real IIS app-pool identity (M5).
  143. ' This is the genuinely open question SPEC SS10/SS15's "validate app pool
  144. ' identity... where applicable" discipline calls for: WSH/direct component
  145. ' tests only prove the contract under the interactive dev account. SQL
  146. ' auth over TCP (not LocalDB's Windows-integrated named pipes) doesn't
  147. ' depend on the caller's OS identity, but this is still verified for real
  148. ' here rather than assumed, exactly because this route runs inside the
  149. ' real worker process under ApplicationPoolIdentity - see
  150. ' docs/DECISIONS.md for the LocalDB attempt that failed this exact check.
  151. ' NOTE: this probes ADODB.Connection directly, bypassing WscMvc.Database,
  152. ' solely to see the real underlying driver error - Database.Open
  153. ' deliberately discards Err.Description (SPEC SS10: never leak connection
  154. ' strings/internals to a client), which is correct for the production
  155. ' error boundary but useless for diagnosing *why* connectivity fails.
  156. ' SelfTestController is the one place intentionally exempted from that
  157. ' rule (see file header comment).
  158. Dim rawConn, dbOk, dbDetail, dbRs, dbSkipped
  159. dbOk = False
  160. dbDetail = ""
  161. dbSkipped = False
  162. If Len(Trim(dbConnectionString)) = 0 Then
  163. ' No db.connectionstring provisioned on this deployment - an
  164. ' environment-provisioning fact, not a framework defect, so this
  165. ' reports as passing-but-skipped rather than dragging down "ok"
  166. ' (same NOT-RUN-not-FAIL discipline as tests/Test-Components.vbs).
  167. dbSkipped = True
  168. dbOk = True
  169. dbDetail = "skipped: db.connectionstring not provisioned on this deployment"
  170. End If
  171. If Not dbSkipped Then
  172. On Error Resume Next
  173. Set rawConn = CreateObject("ADODB.Connection")
  174. If Err.Number <> 0 Then
  175. dbDetail = "CreateObject: " & Err.Description
  176. Err.Clear
  177. End If
  178. On Error Goto 0
  179. End If
  180. If Len(dbDetail) = 0 Then
  181. On Error Resume Next
  182. rawConn.Open dbConnectionString
  183. If Err.Number <> 0 Then
  184. dbDetail = "Open: " & Err.Number & " - " & Err.Description
  185. Err.Clear
  186. End If
  187. On Error Goto 0
  188. End If
  189. If Len(dbDetail) = 0 Then
  190. On Error Resume Next
  191. Set dbRs = rawConn.Execute("SELECT 1")
  192. If Err.Number <> 0 Then
  193. dbDetail = "Execute: " & Err.Number & " - " & Err.Description
  194. Err.Clear
  195. Else
  196. dbOk = True
  197. dbRs.Close
  198. End If
  199. On Error Goto 0
  200. End If
  201. On Error Resume Next
  202. If Not rawConn Is Nothing Then rawConn.Close
  203. Err.Clear
  204. On Error Goto 0
  205. checks = AppendCheck(checks, "database_connectivity_under_app_pool_identity", dbOk, dbDetail)
  206. allPass = allPass And dbOk
  207. Set rawConn = Nothing
  208. Set ctx1 = Nothing
  209. Set ctx2 = Nothing
  210. Set ctxUnknown = Nothing
  211. Set ctxPost = Nothing
  212. Set ctxDelete = Nothing
  213. Set router = Nothing
  214. Set app = Nothing
  215. body = "{""ok"":" & LCase(CStr(allPass)) & ",""checks"":[" & checks & "]}"
  216. End Sub
  217. Function AppendCheck(checksSoFar, name, pass, detail)
  218. Dim entry
  219. entry = "{""name"":""" & JsonEscape(name) & """,""pass"":" & LCase(CStr(pass)) & _
  220. ",""detail"":""" & JsonEscape(detail) & """}"
  221. If Len(checksSoFar) = 0 Then
  222. AppendCheck = entry
  223. Else
  224. AppendCheck = checksSoFar & "," & entry
  225. End If
  226. End Function
  227. Function JsonEscape(s)
  228. Dim result
  229. result = s
  230. result = Replace(result, "\", "\\")
  231. result = Replace(result, """", "\""")
  232. result = Replace(result, vbCrLf, "\n")
  233. result = Replace(result, vbCr, "\n")
  234. result = Replace(result, vbLf, "\n")
  235. result = Replace(result, vbTab, "\t")
  236. JsonEscape = result
  237. End Function
  238. ]]>
  239. </script>
  240. </component>

Powered by TurnKey Linux.