blob: 6dadf11db11c93a14c264176018250b88c22c952 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
use maka_agent_facts::event::EventWrite;
use maka_agent_facts::event::Fact;
use maka_agent_facts::event::Invocation;
use maka_agent_facts::event::RuntimeEvent;
use maka_agent_facts::input::InvocationInput;
use maka_event_log::{EventLog, StoreError, sessions::SessionMutation};
use serde_json::{Value, json};
#[tokio::test]
async fn metadata_cas_noop_and_reopen_preserve_activity_fingerprint_and_active_execution() {
let temp = tempfile::tempdir().unwrap();
let path = temp.path().join("events.sqlite");
let log = EventLog::open(&path).await.unwrap();
log.create_session(
"session",
"original-create",
&json!({"name":"initial","flag":false}),
10,
)
.await
.unwrap();
let invocation = Invocation {
session_id: "session".into(),
turn_id: "turn".into(),
run_id: "run".into(),
invocation_id: "invocation".into(),
};
log.append(
&EventWrite::plain(
(RuntimeEvent::new(
invocation,
Fact::InvocationOpened {
configuration: None,
input: InvocationInput::Message {
source_messages: Vec::new(),
content: "active".into(),
request_fingerprint: None,
},
},
))
.clone(),
)
.unwrap(),
)
.await
.unwrap();
let events = log.prefix(32, 65536).await.unwrap();
// Invocation opening advances the public Session revision as well.
assert_eq!(
log.get_session::<Value>("session")
.await
.unwrap()
.unwrap()
.revision,
2
);
let initial_catalog = log
.list_sessions::<Value>(None, None, 32)
.await
.unwrap()
.revision;
let result = log
.update_session_metadata("session", 2, |value: &mut Value| {
value["name"] = json!("renamed");
value["flag"] = json!(true);
Ok(())
})
.await
.unwrap();
let SessionMutation::Committed(updated) = result else {
panic!("expected committed update");
};
assert_eq!(updated.revision, 3);
assert_eq!((updated.created_at, updated.updated_at), (10, 10));
assert_eq!(updated.configuration, json!({"name":"renamed","flag":true}));
let changed_catalog = log
.list_sessions::<Value>(None, None, 32)
.await
.unwrap()
.revision;
assert_ne!(initial_catalog, changed_catalog);
let result = log
.update_session_metadata::<Value, _>("session", 2, |_| {
panic!("CAS must precede policy/no-op")
})
.await
.unwrap();
assert!(matches!(
result,
SessionMutation::RevisionConflict {
expected: 2,
actual: 3
}
));
let SessionMutation::Committed(unchanged) = log
.update_session_metadata("session", 3, move |value: &mut Value| {
value["name"] = json!("renamed");
Ok(())
})
.await
.unwrap()
else {
panic!("current-revision no-op must succeed");
};
assert_eq!(unchanged, updated);
let error = log
.update_session_metadata("session", 3, move |value: &mut Value| {
value["name"] = json!("x".repeat(65536));
Err(StoreError::InvalidTransition("policy refused".into()))
})
.await;
assert!(error.is_err());
assert_eq!(
changed_catalog,
log.list_sessions::<Value>(None, None, 32)
.await
.unwrap()
.revision
);
assert_eq!(
Some(updated.clone()),
log.get_session::<Value>("session").await.unwrap()
);
assert_eq!(
serde_json::to_vec(&events).unwrap(),
serde_json::to_vec(&log.prefix(32, 65536).await.unwrap()).unwrap()
);
log.close().await.unwrap();
let log = EventLog::open(&path).await.unwrap();
assert_eq!(
Some(updated),
log.probe_session_create::<Value>("session", "original-create")
.await
.unwrap()
);
assert_eq!(
changed_catalog,
log.list_sessions::<Value>(None, None, 32)
.await
.unwrap()
.revision
);
assert_eq!(
serde_json::to_vec(&events).unwrap(),
serde_json::to_vec(&log.prefix(32, 65536).await.unwrap()).unwrap()
);
assert!(matches!(
log.update_session_metadata::<Value, _>("missing", 1, |_| Ok(()))
.await,
Err(StoreError::SessionNotFound)
));
}