This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch nexus-portal
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git


The following commit(s) were added to refs/heads/nexus-portal by this push:
     new aecc2b034 Enhance the AMIE baseline scenario with 
request_account_create packets and varied user roles
aecc2b034 is described below

commit aecc2b0343634eaf63dda782c93b90d7ca4e9bd6
Author: lahiruj <[email protected]>
AuthorDate: Tue Jun 16 03:06:55 2026 -0400

    Enhance the AMIE baseline scenario with request_account_create packets and 
varied user roles
---
 .../AMIE-Processor/mock-server/mock-amie-server.py |  98 +++++++++-
 .../pipeline/baseline_integration_test.go          |  67 +++----
 .../testdata/scenarios/baseline.yaml               | 204 ++++++++++++++-------
 3 files changed, 255 insertions(+), 114 deletions(-)

diff --git a/connectors/ACCESS/AMIE-Processor/mock-server/mock-amie-server.py 
b/connectors/ACCESS/AMIE-Processor/mock-server/mock-amie-server.py
index 625417335..8a04c0066 100644
--- a/connectors/ACCESS/AMIE-Processor/mock-server/mock-amie-server.py
+++ b/connectors/ACCESS/AMIE-Processor/mock-server/mock-amie-server.py
@@ -38,6 +38,11 @@ replied_packets = {}
 packet_counter = 900000
 stats = {"created": 0, "fetched": 0, "replied": 0}
 
+# Maps GrantNumber → Custos project UUID, populated as notify_project_create
+# replies arrive. Packets carrying a "__GRANT__<GN>" placeholder for ProjectID
+# are held back from /packets until the GrantNumber resolves here.
+grant_to_project_id = {}
+
 SCENARIOS_DIR = Path(__file__).parent / "scenarios"
 DEV_EMAIL = os.getenv("DEV_EMAIL", "").strip()
 
@@ -534,8 +539,8 @@ def gen_baseline_scenario():
             "UserPersonID": "bl-pi-001-user",
             "UserGlobalID": "bl-pi-001",
             "UserFirstName": "Pat",
-            "UserLastName": "First-Updated",
-            "UserEmail": "[email protected]",
+            "UserLastName": "Madison",
+            "UserEmail": "[email protected]",
             "UserOrganization": "Baseline Org",
             "UserOrgCode": "BASELINE",
             "NsfStatusCode": "AC",
@@ -556,6 +561,58 @@ def gen_baseline_scenario():
                 "/DC=EDU/CN=patfirst",
             ],
         }),
+        # request_account_create packets. ProjectID is a placeholder filled
+        # in from the matching notify_project_create reply. PI memberships
+        # come from request_project_create; these cover the non-PI roles.
+
+        # BL-001 CO_PI
+        make_packet("request_account_create", {
+            "ProjectID": "__GRANT__BL-001",
+            "GrantNumber": "BL-001",
+            "UserPersonID": "bl-copi-001-person",
+            "UserGlobalID": "bl-copi-001",
+            "UserFirstName": "Casey",
+            "UserLastName": "Collaborator",
+            "UserEmail": "[email protected]",
+            "UserOrganization": "Baseline Org",
+            "UserOrgCode": "BASELINE",
+            "NsfStatusCode": "AC",
+            "UserDnList": ["/C=US/O=Baseline Org/CN=Casey Collaborator"],
+            "UserRole": "CO_PI",
+            "ResourceList": ["baseline-cluster.example.edu"],
+        }),
+        # BL-001 MEMBER
+        make_packet("request_account_create", {
+            "ProjectID": "__GRANT__BL-001",
+            "GrantNumber": "BL-001",
+            "UserPersonID": "bl-user-001-person",
+            "UserGlobalID": "bl-user-001",
+            "UserFirstName": "Riley",
+            "UserLastName": "Researcher",
+            "UserEmail": "[email protected]",
+            "UserOrganization": "Baseline Org",
+            "UserOrgCode": "BASELINE",
+            "NsfStatusCode": "AC",
+            "UserDnList": ["/C=US/O=Baseline Org/CN=Riley Researcher"],
+            "UserRole": "MEMBER",
+            "ResourceList": ["baseline-cluster.example.edu"],
+        }),
+        # BL-002 ALLOCATION_MANAGER
+        make_packet("request_account_create", {
+            "ProjectID": "__GRANT__BL-002",
+            "GrantNumber": "BL-002",
+            "UserPersonID": "bl-mgr-002-person",
+            "UserGlobalID": "bl-mgr-002",
+            "UserFirstName": "Morgan",
+            "UserLastName": "Manager",
+            "UserEmail": "[email protected]",
+            "UserOrganization": "Baseline Org",
+            "UserOrgCode": "BASELINE",
+            "NsfStatusCode": "AC",
+            "UserDnList": ["/C=US/O=Baseline Org/CN=Morgan Manager"],
+            "UserRole": "ALLOCATION_MANAGER",
+            "ResourceList": ["baseline-cluster.example.edu"],
+        }),
         make_packet("inform_transaction_complete", {
             "StatusCode": "Success",
             "Message": "Baseline complete",
@@ -570,17 +627,41 @@ def gen_baseline_scenario():
 def get_packets(site):
     if not pending_packets:
         return jsonify([])
-    batch = list(pending_packets)
-    pending_packets.clear()
-    stats["fetched"] += len(batch)
-    app.logger.info(f"Serving {len(batch)} packets to site {site}")
-    return jsonify(batch)
+    ready, holdback = [], []
+    for pkt in pending_packets:
+        pid = pkt.get("body", {}).get("ProjectID", "")
+        if isinstance(pid, str) and pid.startswith("__GRANT__"):
+            gn = pid[len("__GRANT__"):]
+            resolved = grant_to_project_id.get(gn)
+            if resolved:
+                pkt["body"]["ProjectID"] = resolved
+                ready.append(pkt)
+            else:
+                holdback.append(pkt)
+        else:
+            ready.append(pkt)
+    pending_packets[:] = holdback
+    if not ready:
+        return jsonify([])
+    stats["fetched"] += len(ready)
+    app.logger.info(f"Serving {len(ready)} packets to site {site}")
+    return jsonify(ready)
 
 
 @app.route("/packets/<site>/<int:packet_rec_id>/reply", methods=["POST"])
 def reply_to_packet(site, packet_rec_id):
-    replied_packets[packet_rec_id] = request.get_json(silent=True)
+    payload = request.get_json(silent=True) or {}
+    replied_packets[packet_rec_id] = payload
     stats["replied"] += 1
+    # Capture the Custos UUID from notify_project_create so the holdback
+    # packets carrying "__GRANT__<GN>" can resolve.
+    if payload.get("type") == "notify_project_create":
+        body = payload.get("body", {}) or {}
+        gn = body.get("GrantNumber")
+        pid = body.get("ProjectID")
+        if gn and pid:
+            grant_to_project_id[gn] = pid
+            app.logger.info(f"Captured GrantNumber {gn} -> ProjectID {pid}")
     return jsonify({"message": "Reply accepted"}), 200
 
 
@@ -588,6 +669,7 @@ def reply_to_packet(site, packet_rec_id):
 def reset(site):
     pending_packets.clear()
     replied_packets.clear()
+    grant_to_project_id.clear()
     stats["created"] = 0
     stats["fetched"] = 0
     stats["replied"] = 0
diff --git 
a/connectors/ACCESS/AMIE-Processor/pipeline/baseline_integration_test.go 
b/connectors/ACCESS/AMIE-Processor/pipeline/baseline_integration_test.go
index 29c56ffa3..f6630b855 100644
--- a/connectors/ACCESS/AMIE-Processor/pipeline/baseline_integration_test.go
+++ b/connectors/ACCESS/AMIE-Processor/pipeline/baseline_integration_test.go
@@ -24,44 +24,36 @@ import (
        "time"
 )
 
-// TestPipeline_BaselineDeterminism, runs the canonical baseline scenario
-// end-to-end against the real mock-amie server, drains, and asserts every
-// total_count from
-// `connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml`.
-//
-// This is a *determinism* test, not a *correctness* test. It locks
-// in "same packets in → same row counts out" so future handler / scenario
-// changes get caught. If baseline.yaml changes, this test changes with it ,
-// the YAML is the source of truth here.
+// TestPipeline_BaselineDeterminism runs the baseline scenario end-to-end and
+// asserts the row counts from baseline.yaml. If baseline.yaml changes, this
+// test changes with it.
 func TestPipeline_BaselineDeterminism(t *testing.T) {
        pipe := newTestPipeline(t)
        defer pipe.stop()
 
        pipe.fireScenario(t, "baseline")
-       decoded := pipe.waitForDrain(t, 9, 90*time.Second)
+       decoded := pipe.waitForDrain(t, 12, 90*time.Second)
 
-       // Expected totals come straight from
-       // connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml.
-       // Field references in comments are the YAML section.
+       // Counts match baseline.yaml.
        expectations := []struct {
                table string
                want  int
        }{
-               {"amie_packets", 9},                   // packets.total_count
-               {"amie_processing_errors", 0},         // not_expected
-               {"organizations", 1},                  // 
tables.organizations.total_count
-               {"users", 2},                          // 
tables.users.total_count
-               {"user_identities", 2},                // 
tables.user_identities.total_count
-               {"projects", 2},                       // 
tables.projects.total_count
-               {"compute_allocations", 2},            // 
tables.compute_allocations.total_count
-               {"compute_allocation_diffs", 1},       // 
tables.compute_allocation_diffs.total_count
-               {"amie_user_dns", 2},                  // 
tables.amie_user_dns.total_count
-               {"amie_audit_extras", 35},             // 
audit_log.total_count. One extras row per AMIE audit_events row
-               {"compute_cluster_users", 1},          // 
tables.compute_cluster_users.total_count (survivor's PI CCU; merge dedups Sam's)
-               {"compute_allocation_memberships", 0}, // not_expected
+               {"amie_packets", 12},
+               {"amie_processing_errors", 0},
+               {"organizations", 1},
+               {"users", 5},
+               {"user_identities", 5},
+               {"projects", 2},
+               {"compute_allocations", 2},
+               {"compute_allocation_diffs", 1},
+               {"amie_user_dns", 2},
+               {"amie_audit_extras", 52},
+               {"compute_cluster_users", 4},
+               {"compute_allocation_memberships", 5},
        }
-       if decoded != 9 {
-               t.Errorf("decoded packets: got %d, want 9", decoded)
+       if decoded != 12 {
+               t.Errorf("decoded packets: got %d, want 12", decoded)
        }
        for _, e := range expectations {
                if got := countRows(t, pipe.db, e.table); got != e.want {
@@ -69,30 +61,29 @@ func TestPipeline_BaselineDeterminism(t *testing.T) {
                }
        }
 
-       // AMIE audit rows now live in audit_events with source='amie'; the
-       // connector-specific (packet_id, event_id) lives in amie_audit_extras.
-       // The two row counts must match.
+       // audit_events (source='amie') and amie_audit_extras carry equal 
counts.
        var amieAuditEvents int
        if err := pipe.db.Get(&amieAuditEvents,
                "SELECT COUNT(*) FROM audit_events WHERE source = 'amie'",
        ); err != nil {
                t.Fatalf("count amie audit_events: %v", err)
        }
-       if amieAuditEvents != 35 {
-               t.Errorf("audit_events source='amie': got %d, want 35", 
amieAuditEvents)
+       if amieAuditEvents != 52 {
+               t.Errorf("audit_events source='amie': got %d, want 52", 
amieAuditEvents)
        }
 
-       // Audit-by-action breakdown also per baseline.yaml audit_log.by_action.
+       // audit_log.by_action.
        actionCounts := []struct {
                action string
                want   int
        }{
-               {"PACKET_RECEIVED", 9},
-               {"CREATE_PERSON", 3},
-               {"CREATE_ACCOUNT", 3},
+               {"PACKET_RECEIVED", 12},
+               {"CREATE_PERSON", 6},
+               {"CREATE_ACCOUNT", 6},
                {"CREATE_PROJECT", 3},
                {"CREATE_ALLOCATION", 3},
-               {"REPLY_SENT", 8},
+               {"CREATE_MEMBERSHIP", 5},
+               {"REPLY_SENT", 11},
                {"PERSIST_DNS", 3},
                {"UPDATE_PERSON", 1},
                {"MERGE_PERSONS", 1},
@@ -110,7 +101,7 @@ func TestPipeline_BaselineDeterminism(t *testing.T) {
                }
        }
 
-       // Every processing event ended SUCCEEDED per baseline.yaml 
processing_events.
+       // processing_events.by_status: all SUCCEEDED.
        var nonSucceeded int
        if err := pipe.db.Get(&nonSucceeded,
                "SELECT COUNT(*) FROM amie_processing_events WHERE status != 
'SUCCEEDED'",
diff --git a/connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml 
b/connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml
index 6834377b0..41ac5504e 100644
--- a/connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml
+++ b/connectors/ACCESS/AMIE-Processor/testdata/scenarios/baseline.yaml
@@ -1,28 +1,17 @@
-# Mock scenario: baseline
+# Baseline scenario expectations. Packets are defined in
+# mock-server.py::gen_baseline_scenario. Portal dev rows that AMIE cannot
+# produce (resources, rates, usage, change requests) come from
+# dev_portal_data.sql, applied after this scenario drains.
 #
-# Hardcoded values in mock-server.py::gen_baseline_scenario. Used as the
-# canonical integration-test fixture for the connector.
-#
-# Covers: request_project_create (initial + supplement), request_user_modify,
-# request_person_merge, data_project_create, data_account_create,
-# inform_transaction_complete.
-#
-# NOT covered (handlers need the Custos-assigned project UUID, which the mock
-# can't supply): request_account_create, request_account_inactivate,
-# request_account_reactivate, request_project_inactivate, 
request_project_reactivate.
-# Tables left empty as a result: compute_allocation_memberships.
-# Status-flip code paths on projects/allocations/memberships are also 
unexercised.
-# compute_cluster_users IS populated because request_project_create provisions
-# a PI cluster user via the POSIX allocator.
+# request_account_create packets use ProjectID="__GRANT__<GN>" placeholders.
+# The mock fills them in with the Custos UUID returned by 
notify_project_create.
 
 scenario:
   name: baseline
-  description: 9 hardcoded packets exercising every handler the mock can drive 
without reply sequencing.
+  description: 12 hardcoded packets covering the AMIE handlers the mock can 
drive.
   determinism: full
-  # Expectations assume packets are decoded and handled in mock-emission order.
-  # The connector's worker is single-threaded today; if that changes, the
-  # post-merge counts (amie_user_dns=3, projects.project_pi_id, survivor column
-  # values) all become race-dependent.
+  # Counts assume packets are decoded in mock-emission order. The worker is
+  # single-threaded, so post-merge counts depend on this ordering.
   ordering: strict
 
 trigger:
@@ -44,13 +33,14 @@ trigger:
 expectations:
 
   packets:
-    total_count: 9
+    total_count: 12
     by_type_status:
       - { type: request_project_create,      status: DECODED, count: 3 }
       - { type: data_project_create,         status: DECODED, count: 1 }
       - { type: data_account_create,         status: DECODED, count: 1 }
       - { type: request_user_modify,         status: DECODED, count: 2 }
       - { type: request_person_merge,        status: DECODED, count: 1 }
+      - { type: request_account_create,      status: DECODED, count: 3 }
       - { type: inform_transaction_complete, status: DECODED, count: 1 }
 
   tables:
@@ -61,40 +51,41 @@ expectations:
         - { originated_id: BASELINE, name: Baseline Org }
 
     users:
-      total_count: 2
+      # Pat is the merge survivor; Sam was MERGED into Pat.
+      total_count: 5
       rows:
-        - { first_name: Pat, last_name: First-Updated, email: 
[email protected], status: ACTIVE,
-            organization_id: { from: "organizations.id where 
originated_id=BASELINE" } }
-        - { first_name: Sam, last_name: Second, email: 
[email protected], status: MERGED,
-            organization_id: { from: "organizations.id where 
originated_id=BASELINE" } }
+        - { first_name: Pat,    last_name: Madison, email: 
[email protected], status: ACTIVE }
+        - { first_name: Sam,    last_name: Second,        email: 
[email protected],        status: MERGED }
+        - { first_name: Casey,  last_name: Collaborator,  email: 
[email protected],      status: ACTIVE }
+        - { first_name: Riley,  last_name: Researcher,    email: 
[email protected],    status: ACTIVE }
+        - { first_name: Morgan, last_name: Manager,       email: 
[email protected],    status: ACTIVE }
 
     user_identities:
-      total_count: 2
+      total_count: 5
       rows:
         - { source: access, external_id: bl-pi-001,
-            email: [email protected],
-            user_id: { from: "users.id where 
[email protected]" },
+            email: [email protected],
+            user_id: { from: "users.id where 
[email protected]" },
             metadata: { regex: '.*"org_code":"BASELINE".*' } }
-        # bl-pi-002's row is reassigned to the survivor by 
MergeUsers.ReassignUser.
+        # Sam's identity row was reassigned to Pat by the merge.
         - { source: access, external_id: bl-pi-002,
             email: [email protected],
-            user_id: { from: "users.id where 
[email protected]" } }
+            user_id: { from: "users.id where 
[email protected]" } }
 
     projects:
       total_count: 2
       rows:
-        # Handler sets project.title = GrantNumber (NOT ProjectTitle from 
packet).
+        # Handler uses GrantNumber as project.title, not ProjectTitle.
         - { originated_id: BL-001, title: BL-001, origination: access, status: 
ACTIVE,
-            project_pi_id: { from: "users.id where 
[email protected]" } }
-        # BL-002's PI was bl-pi-002 originally; merge reassigned project_pi_id 
to the survivor.
+            project_pi_id: { from: "users.id where 
[email protected]" } }
+        # BL-002 PI was reassigned to Pat by the merge.
         - { originated_id: BL-002, title: BL-002, origination: access, status: 
ACTIVE,
-            project_pi_id: { from: "users.id where 
[email protected]" } }
+            project_pi_id: { from: "users.id where 
[email protected]" } }
 
     compute_allocations:
       total_count: 2
       rows:
-        # initial_su_amount stays at first-delivery value; supplement writes a 
diff row
-        # instead of updating this column. Effective budget = 
initial_su_amount + SUM(diffs.new_su_amount).
+        # Supplement deltas go into compute_allocation_diffs, not into 
initial_su_amount.
         - { name: BL-001, status: ACTIVE, compute_cluster_id: 
"${AMIE_CLUSTER_ID}",
             initial_su_amount: 10000,
             start_time: "2026-01-01 00:00:00", end_time: "2026-12-31 00:00:00",
@@ -112,50 +103,58 @@ expectations:
             description: "AMIE SUPPLEMENT of 5000 SUs" }
 
     amie_user_dns:
-      # 3 DNs land on the survivor after merge; the trailing ActionType=delete
-      # request_user_modify removes "/DC=EDU/CN=patfirst", leaving 2.
-      # Connector-local table; user_id references core users.id by value.
+      # 3 DNs end up on the survivor; the trailing request_user_modify (delete)
+      # removes "/DC=EDU/CN=patfirst", leaving 2.
       total_count: 2
       rows:
         - { dn: "/C=US/O=Baseline Org/CN=Pat First Extra",
-            user_id: { from: "users.id where 
[email protected]" } }
-        # data_account_create added this DN to bl-pi-002; merge reassigned it 
to survivor.
+            user_id: { from: "users.id where 
[email protected]" } }
+        # Originally Sam's DN; reassigned to Pat by the merge.
         - { dn: "/C=US/O=Baseline Org/CN=Sam Second",
-            user_id: { from: "users.id where 
[email protected]" } }
+            user_id: { from: "users.id where 
[email protected]" } }
 
     compute_cluster_users:
-      # request_project_create now provisions a CCU for the PI via the POSIX
-      # allocator. BL-001 (#1 + supplement) creates Pat's CCU once. BL-002
-      # (#3) creates Sam's CCU. The merge then deletes Sam's CCU on Pat's
-      # cluster (cluster overlap dedup), leaving Pat's row only.
-      total_count: 1
+      # PI CCUs come from request_project_create; the merge dedups Sam's 
against
+      # Pat's. request_account_create packets add CCUs for Casey, Riley, 
Morgan.
+      total_count: 4
       rows:
         - { compute_cluster_id: "${AMIE_CLUSTER_ID}",
             local_username: custos-pfirst,
-            user_id: { from: "users.id where 
[email protected]" } }
+            user_id: { from: "users.id where 
[email protected]" } }
+
+    compute_allocation_memberships:
+      # PI memberships come from request_project_create; non-PI roles from
+      # request_account_create.
+      #   BL-001: Pat (PI), Casey (CO_PI), Riley (MEMBER)
+      #   BL-002: Pat (PI, post-merge), Morgan (ALLOCATION_MANAGER)
+      total_count: 5
+      by_role:
+        PI: 2
+        CO_PI: 1
+        ALLOCATION_MANAGER: 1
+        MEMBER: 1
 
   audit_log:
-    # AMIE audit rows live in audit_events (source='amie'); the 
connector-specific
-    # (packet_id, event_id) refs live in amie_audit_extras joined on 
audit_event_id.
-    # `total_count` here = count over audit_events WHERE source='amie'
-    #                    = count over amie_audit_extras.
-    total_count: 35
+    # audit_events (source='amie') and amie_audit_extras carry the same count;
+    # one row each per AMIE audit.
+    total_count: 52
     by_action:
-      PACKET_RECEIVED: 9      # worker writes one root structural marker per 
packet so the trace tree has a root anchor
-      CREATE_PERSON: 3        # all 3 request_project_create packets audit 
CREATE_PERSON (re-use audited too)
-      CREATE_ACCOUNT: 3       # PI CCU provisioning audited on every 
request_project_create (re-use audited too)
+      PACKET_RECEIVED: 12     # one per packet
+      CREATE_PERSON: 6        # 3 project_create + 3 account_create
+      CREATE_ACCOUNT: 6       # 3 project_create + 3 account_create
       CREATE_PROJECT: 3
-      CREATE_ALLOCATION: 3    # supplement-delivery still audits 
CREATE_ALLOCATION (known M1: diff is the actual write)
-      REPLY_SENT: 8           # inform_transaction_complete does not reply
-      PERSIST_DNS: 3          # 2 from data_*, 1 from request_user_modify 
delete (DN delete: -1)
+      CREATE_ALLOCATION: 3    # supplement-delivery still audits 
CREATE_ALLOCATION
+      CREATE_MEMBERSHIP: 5    # 2 PIs + 3 account_create
+      REPLY_SENT: 11          # everything except inform_transaction_complete
+      PERSIST_DNS: 3          # 2 from data_*, 1 delete from 
request_user_modify
       UPDATE_PERSON: 1
       MERGE_PERSONS: 1
       TRANSACTION_COMPLETE: 1
 
   processing_events:
-    total_count: 9
+    total_count: 12
     by_status:
-      SUCCEEDED: 9
+      SUCCEEDED: 12
     not_expected_statuses:
       - RUNNING
       - NEW
@@ -164,9 +163,78 @@ expectations:
       - PERMANENTLY_FAILED
 
   not_expected:
-    - compute_allocation_memberships
     - amie_processing_errors
 
+# ---------------------------------------------------------------------------
+# Seed rows from dev_portal_data.sql, applied after baseline drains. These
+# tables aren't reachable from AMIE handlers; the seed exists so portal pages
+# render meaningful content. Counts are lower bounds.
+# ---------------------------------------------------------------------------
+
+seed_rows:
+
+  compute_allocation_resources:
+    minimum_count: 2        # CPU + GPU, cluster-scoped
+    rows:
+      - { id: res-cpu, name: "CPU Service Units", resource_type: CPU_HOURS,
+          compute_cluster_id: "${AMIE_CLUSTER_ID}" }
+      - { id: res-gpu, name: "GPU Service Units", resource_type: GPU_HOURS,
+          compute_cluster_id: "${AMIE_CLUSTER_ID}" }
+
+  compute_allocation_resource_mappings:
+    minimum_count: 3        # CPU on both allocations, GPU on BL-001
+    rows:
+      - { compute_allocation_id: { from: "compute_allocations.id where 
name=BL-001" },
+          compute_allocation_resource_id: res-cpu, resource_amount: 10000 }
+      - { compute_allocation_id: { from: "compute_allocations.id where 
name=BL-002" },
+          compute_allocation_resource_id: res-cpu, resource_amount: 10000 }
+      - { compute_allocation_id: { from: "compute_allocations.id where 
name=BL-001" },
+          compute_allocation_resource_id: res-gpu, resource_amount: 200 }
+
+  compute_allocation_resource_rates:
+    minimum_count: 2
+    rows:
+      - { id: rate-cpu, compute_allocation_resource_id: res-cpu, rate: 1.0 }
+      - { id: rate-gpu, compute_allocation_resource_id: res-gpu, rate: 10.0 }
+
+  compute_allocation_usages:
+    minimum_count: 2        # one sample job per baseline allocation
+    rows:
+      - { compute_allocation_id: { from: "compute_allocations.id where 
name=BL-001" },
+          used_su_amount: 250.5, compute_allocation_resource_id: res-cpu }
+      - { compute_allocation_id: { from: "compute_allocations.id where 
name=BL-002" },
+          used_su_amount: 250.5, compute_allocation_resource_id: res-cpu }
+
+  compute_allocation_change_requests:
+    minimum_count: 1        # one PENDING request on BL-001
+    rows:
+      - { id: chreq-bl001, change_status: PENDING, requested_su_amount: 25000,
+          requested_status: ACTIVE,
+          compute_allocation_id: { from: "compute_allocations.id where 
name=BL-001" },
+          requester_id: dev-researcher }
+
+  compute_allocation_change_request_events:
+    minimum_count: 2        # CREATED + COMMENTED
+    rows:
+      - { compute_allocation_change_request_id: chreq-bl001, event_type: 
CREATED }
+      - { compute_allocation_change_request_id: chreq-bl001, event_type: 
COMMENTED }
+
+  compute_allocation_membership_resource_overrides:
+    minimum_count: 1
+    rows:
+      - { compute_allocation_resource_id: res-gpu, override_resource_amount: 
50,
+          compute_allocation_membership_id: { from: 
"compute_allocation_memberships.id where 
compute_allocation_id=(compute_allocations.id where name=BL-001)" } }
+
+  user_privileges:
+    minimum_count: 6        # dev-admin gets all 6 portal privileges via seed
+    rows:
+      - { user_id: dev-admin, privilege: "amie:read" }
+      - { user_id: dev-admin, privilege: "amie:write" }
+      - { user_id: dev-admin, privilege: "hpc:read" }
+      - { user_id: dev-admin, privilege: "hpc:write" }
+      - { user_id: dev-admin, privilege: "signer:read" }
+      - { user_id: dev-admin, privilege: "signer:write" }
+
 verification_queries:
 
   - name: packet status by type
@@ -182,7 +250,7 @@ verification_queries:
   - name: survivor + retiring user state
     sql: SELECT email, status FROM users ORDER BY email;
     expect: |
-      [email protected], ACTIVE
+      [email protected], ACTIVE
       [email protected],        MERGED
 
   - name: supplement recorded as diff (not new allocation)
@@ -195,14 +263,14 @@ verification_queries:
 
   - name: merge consolidated identity-forward state to survivor
     sql: |
-      SELECT 'user_identities' AS t, COUNT(*) AS n_on_survivor FROM 
user_identities WHERE user_id = (SELECT id FROM users WHERE 
email='[email protected]')
+      SELECT 'user_identities' AS t, COUNT(*) AS n_on_survivor FROM 
user_identities WHERE user_id = (SELECT id FROM users WHERE 
email='[email protected]')
       UNION ALL
-      SELECT 'amie_user_dns',   COUNT(*)                       FROM 
amie_user_dns   WHERE user_id = (SELECT id FROM users WHERE 
email='[email protected]')
+      SELECT 'amie_user_dns',   COUNT(*)                       FROM 
amie_user_dns   WHERE user_id = (SELECT id FROM users WHERE 
email='[email protected]')
       UNION ALL
-      SELECT 'projects_as_pi',  COUNT(*)                       FROM projects   
     WHERE project_pi_id = (SELECT id FROM users WHERE 
email='[email protected]');
+      SELECT 'projects_as_pi',  COUNT(*)                       FROM projects   
     WHERE project_pi_id = (SELECT id FROM users WHERE 
email='[email protected]');
     expect: user_identities=2, amie_user_dns=2, projects_as_pi=2
 
-  - name: merge recorded in audit log (no user_merges table; audit is source 
of truth)
+  - name: merge recorded in audit log
     sql: |
       SELECT event_type, entity_type, entity_id, details
       FROM audit_events

Reply via email to