using System; using ArchestrA.GRAccess; class Program { static int Main(string[] args) { // Probe: write to $TestMachine.UpdateTestChangingInt.DeclarationsText (a // package-only ScriptExtension text field) via the TN-537 pattern using // ConfigurableAttributes. Read back through TWO paths to discriminate // between (a) write-side no-op vs (b) read-side staleness: // 1. Same IgObject proxy via obj.ConfigurableAttributes (in-memory edit view) // 2. Fresh galaxy.QueryObjectsByName proxy via .Attributes (runtime view) // // Restores DeclarationsText to empty when done. const string GalaxyName = "ZB"; const string Tagname = "$TestMachine"; const string ScriptName = "UpdateTestChangingInt"; const string FieldName = "DeclarationsText"; const string Marker = "// graccesscli probe marker — TN537 ConfigurableAttributes path\n"; var user = Environment.GetEnvironmentVariable("MX_TEST_USER") ?? ""; var pass = Environment.GetEnvironmentVariable("MX_TEST_PASSWORD") ?? ""; var node = Environment.MachineName; Console.WriteLine($"[probe] connecting to {node} galaxy={GalaxyName} as {user}"); var gr = new GRAccessAppClass(); var galaxies = gr.QueryGalaxies(node); var galaxy = galaxies[GalaxyName]; if (string.IsNullOrEmpty(user)) galaxy.Login(); else galaxy.Login(user, pass); var attrPath = ScriptName + "." + FieldName; // Acquire the target template object. var names = new string[] { Tagname }; var initial = QueryOne(galaxy, names); // Read current value via ConfigurableAttributes (configuration view). var beforeCfg = TryReadString(initial.ConfigurableAttributes, attrPath, "before-cfg"); var beforeRt = TryReadString(initial.Attributes, attrPath, "before-rt"); Console.WriteLine($"[probe] BEFORE cfg={Quote(beforeCfg)} rt={Quote(beforeRt)}"); // Mutate via the canonical TN-537 sequence on the same proxy. Console.WriteLine("[probe] CheckOut..."); initial.CheckOut(); ThrowIfFailed(initial.CommandResult, "CheckOut"); Console.WriteLine("[probe] ConfigurableAttributes[...].SetValue(MxValue)..."); var cfgAttr = initial.ConfigurableAttributes[attrPath]; var v = new MxValueClass(); v.PutString(Marker); cfgAttr.SetValue(v); Console.WriteLine("[probe] Save..."); initial.Save(); ThrowIfFailed(initial.CommandResult, "Save"); Console.WriteLine("[probe] CheckIn..."); initial.CheckIn("graccesscli probe round-trip test"); ThrowIfFailed(initial.CommandResult, "CheckIn"); // Now read back THREE ways: // A. Same proxy (initial), ConfigurableAttributes — possibly stale. // B. Same proxy (initial), Attributes — possibly stale. // C. Fresh proxy from a fresh QueryObjectsByName call. var afterCfgSame = TryReadString(initial.ConfigurableAttributes, attrPath, "after-cfg-same"); var afterRtSame = TryReadString(initial.Attributes, attrPath, "after-rt-same"); Console.WriteLine($"[probe] AFTER (same proxy) cfg={Quote(afterCfgSame)} rt={Quote(afterRtSame)}"); var refreshed = QueryOne(galaxy, names); var afterCfgFresh = TryReadString(refreshed.ConfigurableAttributes, attrPath, "after-cfg-fresh"); var afterRtFresh = TryReadString(refreshed.Attributes, attrPath, "after-rt-fresh"); Console.WriteLine($"[probe] AFTER (fresh proxy) cfg={Quote(afterCfgFresh)} rt={Quote(afterRtFresh)}"); // Restore: write the original value back (or empty if there was none). var restoreTo = beforeCfg ?? ""; Console.WriteLine($"[probe] Restoring DeclarationsText to {Quote(restoreTo)}..."); refreshed.CheckOut(); ThrowIfFailed(refreshed.CommandResult, "CheckOut(restore)"); var restoreAttr = refreshed.ConfigurableAttributes[attrPath]; var rv = new MxValueClass(); rv.PutString(restoreTo); restoreAttr.SetValue(rv); refreshed.Save(); ThrowIfFailed(refreshed.CommandResult, "Save(restore)"); refreshed.CheckIn("graccesscli probe restore"); ThrowIfFailed(refreshed.CommandResult, "CheckIn(restore)"); Console.WriteLine("[probe] Restored."); // Verdict. Console.WriteLine(); Console.WriteLine("=== verdict ==="); Console.WriteLine($" marker landed on same-proxy ConfigurableAttributes: {(afterCfgSame == Marker)}"); Console.WriteLine($" marker landed on same-proxy Attributes : {(afterRtSame == Marker)}"); Console.WriteLine($" marker landed on fresh-proxy ConfigurableAttributes: {(afterCfgFresh == Marker)}"); Console.WriteLine($" marker landed on fresh-proxy Attributes : {(afterRtFresh == Marker)}"); return 0; } static IgObject QueryOne(IGalaxy galaxy, string[] names) { var objs = galaxy.QueryObjectsByName(EgObjectIsTemplateOrInstance.gObjectIsTemplate, ref names); ThrowIfFailed(galaxy.CommandResult, "QueryObjectsByName"); return objs[1]; } static string TryReadString(IAttributes attrs, string name, string label) { try { var attr = attrs[name]; if (attr == null) return null; var val = attr.value; return val?.GetString(); } catch (Exception ex) { Console.WriteLine($"[probe] {label} read threw: {ex.Message}"); return null; } } static void ThrowIfFailed(ICommandResult r, string what) { if (r != null && !r.Successful) throw new InvalidOperationException($"{what} failed: ID={r.ID} Text='{r.Text}' Custom='{r.CustomMessage}'"); } static string Quote(string s) => s == null ? "" : "\"" + s.Replace("\n", "\\n").Replace("\r", "\\r") + "\""; }