Skip to content

Implement the missed test case from codecov #3005

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a6eea79
Implement the missed test case from codecov
bitfriend May 22, 2025
aecb96b
Implement the missed test case from codecov
bitfriend May 22, 2025
594244d
Implement the missed test case from codecov
bitfriend May 22, 2025
67cef6f
Merge remote-tracking branch 'upstream/main' into activate-integratio…
bitfriend May 22, 2025
49473a4
Fix lint error from git workflow
bitfriend May 22, 2025
6f455bd
Implement the missed test case from codecov
bitfriend May 22, 2025
d818fee
Fix lint error from git workflow
bitfriend May 22, 2025
ce350bb
Implement the missed test case from codecov
bitfriend May 22, 2025
ac07611
Implement the missed test case from codecov
bitfriend May 23, 2025
fa93ac0
Merge remote-tracking branch 'upstream/main' into activate-integratio…
bitfriend May 23, 2025
f934802
Implement the missed test case from codecov
bitfriend May 23, 2025
7dc67c0
Implement the missed test case from codecov
bitfriend May 23, 2025
9bfb4bf
Room::room_type() can be replaced with RoomPreview::state_str()
bitfriend May 23, 2025
56e92fb
Implement the missed test case from codecov
bitfriend May 23, 2025
4589d78
Refactory directory structure of rust test
bitfriend May 23, 2025
d05c115
Merge remote-tracking branch 'upstream/main' into activate-integratio…
bitfriend May 23, 2025
6247fdb
Implement the missed test case from codecov
bitfriend May 23, 2025
068505d
Refactor some fns
bitfriend May 23, 2025
33b0f88
Fix typo
bitfriend May 26, 2025
4b54e57
Refactor code
bitfriend May 26, 2025
2d64592
Remove the incorrect comment because timeline doesn't work on space
bitfriend May 26, 2025
4ff9ba9
Add event waiting code to fix the intermittent failure in message red…
bitfriend May 26, 2025
2c274fd
Don't expose API for comment update for now because its UI is not ready
bitfriend May 26, 2025
cf3e911
Merge remote-tracking branch 'upstream/main' into activate-integratio…
bitfriend May 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions native/acter/api.rsh
Original file line number Diff line number Diff line change
Expand Up @@ -1779,9 +1779,6 @@ object Convo {
/// If this function belongs to message object, we may have to load too many message objects in ChatScreen
fn media_binary(event_id: string, thumb_size: Option<ThumbnailSize>) -> Future<Result<buffer<u8>>>;

/// get the user status on this room
fn room_type() -> string;

/// is this a direct message
fn is_dm() -> bool;

Expand Down
2 changes: 1 addition & 1 deletion native/acter/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ pub use bookmarks::Bookmarks;
pub use calendar_events::{CalendarEvent, CalendarEventDraft, CalendarEventUpdateBuilder};
pub use categories::{Categories, CategoriesBuilder};
pub use client::{Client, ClientStateBuilder, HistoryLoadState, LocalUrlPreview, SyncState};
pub use comments::{Comment, CommentDraft, CommentsManager};
pub use comments::{Comment, CommentDraft, CommentUpdateBuilder, CommentsManager};
pub use common::{
duration_from_secs, new_colorize_builder, new_display_builder, new_obj_ref_builder,
new_thumb_size, ComposeDraft, DeviceRecord, MediaSource, OptionBuffer, OptionComposeDraft,
Expand Down
75 changes: 74 additions & 1 deletion native/acter/src/api/comments.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use acter_core::{
events::comments::CommentBuilder,
events::comments::{self, CommentBuilder},
models::{self, can_redact, ActerModel, AnyActerModel},
};
use anyhow::{bail, Result};
Expand Down Expand Up @@ -55,6 +55,14 @@
}

impl Comment {
pub(crate) fn new(client: Client, room: Room, inner: models::Comment) -> Self {
Comment {
client,
room,
inner,
}
}

fn is_joined(&self) -> bool {
matches!(self.room.state(), RoomState::Joined)
}
Expand All @@ -70,6 +78,21 @@
})
}

pub async fn refresh(&self) -> Result<Comment> {
let key = self.inner.event_id().to_owned();
let client = self.client.clone();
let room = self.room.clone();

RUNTIME
.spawn(async move {
let AnyActerModel::Comment(inner) = client.store().get(&key).await? else {
bail!("Refreshing failed. {key} not a comment")

Check warning on line 89 in native/acter/src/api/comments.rs

View check run for this annotation

Codecov / codecov/patch

native/acter/src/api/comments.rs#L89

Added line #L89 was not covered by tests
};
Ok(Comment::new(client, room, inner))
})
.await?
}

pub async fn can_redact(&self) -> Result<bool> {
let sender = self.sender();
let room = self.room.clone();
Expand All @@ -90,6 +113,17 @@
pub fn msg_content(&self) -> MsgContent {
(&self.inner.content).into()
}

pub fn update_builder(&self) -> Result<CommentUpdateBuilder> {
if !self.is_joined() {
bail!("Can only update comments in joined rooms");

Check warning on line 119 in native/acter/src/api/comments.rs

View check run for this annotation

Codecov / codecov/patch

native/acter/src/api/comments.rs#L119

Added line #L119 was not covered by tests
}
Ok(CommentUpdateBuilder {
client: self.client.clone(),
room: self.room.clone(),
inner: self.inner.updater(),
})
}
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -144,6 +178,45 @@
}
}

#[derive(Clone)]
pub struct CommentUpdateBuilder {
client: Client,
room: Room,
inner: comments::CommentUpdateBuilder,
}

impl CommentUpdateBuilder {
pub fn content_text(&mut self, body: String) -> &mut Self {
self.inner.content(TextMessageEventContent::plain(body));
self
}

pub fn content_formatted(&mut self, body: String, html_body: String) -> &mut Self {
self.inner
.content(TextMessageEventContent::html(body, html_body));
self
}

pub async fn send(&self) -> Result<OwnedEventId> {
let room = self.room.clone();
let my_id = self.client.user_id()?;
let inner = self.inner.build()?;

RUNTIME
.spawn(async move {
let permitted = room
.can_user_send_message(&my_id, MessageLikeEventType::RoomMessage)
.await?;
if !permitted {
bail!("No permissions to send message in this room");

Check warning on line 211 in native/acter/src/api/comments.rs

View check run for this annotation

Codecov / codecov/patch

native/acter/src/api/comments.rs#L211

Added line #L211 was not covered by tests
}
let response = room.send(inner).await?;
Ok(response.event_id)
})
.await?
}
}

impl CommentsManager {
pub(crate) async fn new(
client: Client,
Expand Down
10 changes: 0 additions & 10 deletions native/acter/src/api/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,16 +1336,6 @@ impl Room {
.await?
}

pub fn room_type(&self) -> String {
match self.room.state() {
RoomState::Joined => "joined".to_owned(),
RoomState::Left => "left".to_owned(),
RoomState::Invited => "invited".to_owned(),
RoomState::Knocked => "knocked".to_owned(),
RoomState::Banned => "banned".to_owned(),
}
}

fn is_invited(&self) -> bool {
matches!(self.room.state(), RoomState::Invited)
}
Expand Down
5 changes: 3 additions & 2 deletions native/test/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
mod activities;
mod attachment;
mod auth;
mod backup;
mod blurhash;
mod bookmarks;
mod calendar;
mod categories;
mod formatted_body;
mod invitation;
mod media_msg;
mod msg_draft;
mod msg_edit;
mod news;
mod notifications;
Expand All @@ -26,7 +28,6 @@ mod super_invites;
mod sync;
mod tasks;
mod templates;
mod thumbnail;
mod typing;
mod url_previews;
mod verification;
189 changes: 189 additions & 0 deletions native/test/src/tests/attachment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
use acter::ActerModel;
use anyhow::{bail, Result};
use std::{env, io::Write};
use tempfile::NamedTempFile;
use tokio_retry::{
strategy::{jitter, FibonacciBackoff},
Retry,
};

use crate::utils::random_user_with_template;

const TMPL: &str = r#"
version = "0.1"
name = "Smoketest Template"

[inputs]
main = { type = "user", is-default = true, required = true, description = "The starting user" }

[objects]
main_space = { type = "space", is-default = true, name = "{{ main.display_name }}’s pins test space" }

[objects.acter-website-pin]
type = "pin"
title = "Acter Website"
url = "https://acter.global"

[objects.acter-source-pin]
type = "pin"
title = "Acter Source Code"
url = "https://github.com/acterglobal/a3"

[objects.example-data-pin]
type = "pin"
title = "Acter example pin"
content = { body = "example pin data" }
"#;

#[tokio::test]
async fn attachment_can_redact() -> Result<()> {
let _ = env_logger::try_init();
let (user, sync_state, _engine) =
random_user_with_template("attachment_can_redact", TMPL).await?;
sync_state.await_has_synced_history().await?;

let retry_strategy = FibonacciBackoff::from_millis(100).map(jitter).take(10);
let fetcher_client = user.clone();
Retry::spawn(retry_strategy, move || {
let client = fetcher_client.clone();
async move {
if client.pins().await?.len() != 3 {
bail!("not all pins found");
}
Ok(())
}
})
.await?;

let pin = user
.pins()
.await?
.into_iter()
.find(|p| !p.is_link())
.expect("we’ve created one non-link pin");

// START actual attachment on pin

let attachments_manager = pin.attachments().await?;
assert!(!attachments_manager.stats().has_attachments());

// ---- let’s make a attachment

let bytes = include_bytes!("./fixtures/kingfisher.jpg");
let mut jpg_file = NamedTempFile::new()?;
jpg_file.as_file_mut().write_all(bytes)?;

let attachments_listener = attachments_manager.subscribe();
let base_draft = user.image_draft(
jpg_file.path().to_string_lossy().to_string(),
"image/jpeg".to_owned(),
);
let attachment_id = attachments_manager
.content_draft(Box::new(base_draft))
.await?
.send()
.await?;

let retry_strategy = FibonacciBackoff::from_millis(500).map(jitter).take(10);
Retry::spawn(retry_strategy.clone(), || async {
if attachments_listener.is_empty() {
bail!("all still empty");
}
Ok(())
})
.await?;

let attachments = attachments_manager.attachments().await?;
assert_eq!(attachments.len(), 1);
let attachment = attachments
.first()
.expect("first attachment should be available");
assert_eq!(attachment.event_id(), attachment_id);
assert_eq!(attachment.type_str(), "image");
let deletable = attachment.can_redact().await?;
assert!(deletable, "my attachment should be deletable");

Ok(())
}

#[tokio::test]
async fn attachment_download_media() -> Result<()> {
let _ = env_logger::try_init();
let (user, sync_state, _engine) =
random_user_with_template("attachment_download_media", TMPL).await?;
sync_state.await_has_synced_history().await?;

let retry_strategy = FibonacciBackoff::from_millis(100).map(jitter).take(10);
let fetcher_client = user.clone();
Retry::spawn(retry_strategy, move || {
let client = fetcher_client.clone();
async move {
if client.pins().await?.len() != 3 {
bail!("not all pins found");
}
Ok(())
}
})
.await?;

let pin = user
.pins()
.await?
.into_iter()
.find(|p| !p.is_link())
.expect("we’ve created one non-link pin");

// START actual attachment on pin

let attachments_manager = pin.attachments().await?;
assert!(!attachments_manager.stats().has_attachments());

// ---- let’s make a attachment

let bytes = include_bytes!("./fixtures/kingfisher.jpg");
let mut jpg_file = NamedTempFile::new()?;
jpg_file.as_file_mut().write_all(bytes)?;

let attachments_listener = attachments_manager.subscribe();
let base_draft = user.image_draft(
jpg_file.path().to_string_lossy().to_string(),
"image/jpeg".to_owned(),
);
let attachment_id = attachments_manager
.content_draft(Box::new(base_draft))
.await?
.send()
.await?;

let retry_strategy = FibonacciBackoff::from_millis(500).map(jitter).take(10);
Retry::spawn(retry_strategy.clone(), || async {
if attachments_listener.is_empty() {
bail!("all still empty");
}
Ok(())
})
.await?;

let attachments = attachments_manager.attachments().await?;
assert_eq!(attachments.len(), 1);
let attachment = attachments
.first()
.expect("first attachment should be available");
assert_eq!(attachment.event_id(), attachment_id);
assert_eq!(attachment.type_str(), "image");

let dir_path = env::temp_dir().to_string_lossy().to_string();
let downloaded_path = attachment.download_media(None, dir_path).await?;
assert!(
downloaded_path.text().is_some(),
"my attachment should be downloadable"
);

let media_path = attachment.media_path(false).await?;
assert!(
media_path.text().is_some(),
"media path should be accessible if it was downloaded once"
);

Ok(())
}
18 changes: 16 additions & 2 deletions native/test/src/tests/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type = "calendar-event"
title = "Onboarding on Acter"
utc_start = "{{ future(add_days=20).as_rfc3339 }}"
utc_end = "{{ future(add_days=25).as_rfc3339 }}"
locations = [
{ type = "Physical", name = "Denver University" },
{ type = "Virtual", uri = "mxc://acter.global/test", name = "Tech Test Channel" }
]
"#;

#[tokio::test]
Expand All @@ -59,9 +63,19 @@ async fn calendar_smoketest() -> Result<()> {

let spaces = user.spaces().await?;
assert_eq!(spaces.len(), 1);

let main_space = spaces.first().expect("main space should be available");
assert_eq!(main_space.calendar_events().await?.len(), 3);

let cal_events = main_space.calendar_events().await?;
assert_eq!(cal_events.len(), 3);
let main_event = cal_events.first().expect("main event should be available");

let locations = main_event.locations();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

assert_eq!(locations.len(), 2);
assert_eq!(locations[0].location_type(), "Physical");
assert_eq!(locations[0].name().as_deref(), Some("Denver University"));
assert_eq!(locations[1].location_type(), "Virtual");
assert_eq!(locations[1].name().as_deref(), Some("Tech Test Channel"));

Ok(())
}

Expand Down
Loading
Loading