Class PortalRolloutDifferTest

java.lang.Object
scripting.PortalRolloutDifferTest

public class PortalRolloutDifferTest extends Object
Track B(Nashorn → GraalJS)— C3 rollout①:portal 類別黃金參考 differ。

portal 是逐類別 rollout 第一棒(無併發、per-conversation 無狀態)。本測試是把 scripts/portal/ 切到 GraalJS 之前的自動化 gate,對應計畫 C3 的出口條件 「Tier2+Tier3 differ 過關(驗 getInterface SAM)」。

同一 JVM 並存 nashorn-core(黃金參考)與 GraalJS(候選),命名空間不相交,皆由 ScriptEngines.fresh(ScriptEngines.Backend) 建立(順帶驗接縫工廠)。

本檔(C3 第一批:Tier3 全語料 + getInterface SAM 等價)

  • Tier3 解析等價:全 ~825 個 portal 檔的「解析成功與否」在兩引擎必須一致(零 XOR 分歧)。任何 E4X/Nashorn-only 語法殘留都會讓某檔「Nashorn 過、GraalJS 爆」而在此現形。 既有壞腳本(兩引擎皆解析失敗,如未閉合字串)屬行為等價,記錄不擋(見該測試 javadoc)。
  • getInterface SAM 綁定等價:對每個 portal 檔,eval(容忍頂層丟例外,如 org.rise.* 死腳本)後 getInterface(PortalScript.class) 在兩引擎的「非 null」結果必須一致。這驗證 PortalScriptManager 線上實際走的 SAM 映射路徑(:83 getInterface(PortalScript.class)) 在 GraalJS nashorn-compat 下與黃金參考逐檔等價(差異類別 #6,計畫表第 6 列)。

Tier2 代表性轉錄 differ(逐筆 pi.* host 呼叫序列比對、含多載選擇/數值強制/String 身份/ 例外前綴)以 RecordingPortal stub 注入,見本檔下半(隨 recon 選定的 shallow 代表集擴充)。

不需 DB / wz / 網路 / Timer。
  • Constructor Details

    • PortalRolloutDifferTest

      public PortalRolloutDifferTest()
  • Method Details

    • corpusParseAndSamBindingAreEngineEquivalent

      public void corpusParseAndSamBindingAreEngineEquivalent() throws Exception
      scripts/portal/*.js 在 nashorn-core 與 GraalJS 必須等價(非「全部成功」):
      • 解析分歧(XOR)= 零:不得有任何腳本「一引擎解析成功、另一引擎失敗」。這正是 E4X/Nashorn-only 語法殘留會現形之處 —— rollout 硬門檻。
      • SAM 綁定逐檔等價:eval(容忍頂層丟)後 getInterface(PortalScript.class) 的非 null 與否兩引擎必須一致 —— 驗 PortalScriptManager 線上實際走的 SAM 路徑。

      「兩引擎皆解析失敗」≠ 分歧:語料含既有壞腳本 —— 例如 Ravana_Enter.js:75 未閉合 字串字面值、apq_*org.rise.* 殘留 + 小寫 importpackage。這些在線上 今日的 Nashorn 也載不起(PortalScriptManager 接住 ScriptException、記錯誤、傳點 無作用),GraalJS 切換後同樣載不起 → 行為保持。本測試把它們列為「broken-both」記錄到 build/portal-parse-broken-both.txt 與主控台,但當 rollout 阻擋(內容修正屬另案)。 這即 differ 的等價哲學:重點是「兩引擎行為一致」,而非「腳本本身完美」。

      (「死腳本」org.rise/小寫 importpackage 是頂層 eval 才丟、能解析,故落在 broken-both 之外、走 SAM 綁定等價那條:enter 被 hoist → 兩引擎皆綁得到 → parity。)

      Throws:
      Exception
    • tier2TranscriptsAndReturnsMatchAcrossEngines

      public void tier2TranscriptsAndReturnsMatchAcrossEngines() throws Exception
      Throws:
      Exception
    • sharedGraalPortalContextIsUnsafeUnderConcurrentSamEntry

      public void sharedGraalPortalContextIsUnsafeUnderConcurrentSamEntry() throws Exception
      重現危害:單一共用 GraalJS Context 被兩執行緒同時 sam.enter(null)(線上型別化 SAM 路徑) → 拋多執行緒例外(或一度重疊)。證明 flip 的並發危害真實存在、且單執行緒 differ 看不到。
      Throws:
      Exception
    • perScriptNameLockSerializesConcurrentPortalEntry

      public void perScriptNameLockSerializesConcurrentPortalEntry() throws Exception
      佐證修補:套上 per-script-name ReentrantLock (即 PortalScriptManager.executePortalScript 對 GraalJS 路徑的作法)→ 無例外、maxInFlight<=1
      Throws:
      Exception