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