Skip to content
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

Sync solo group after create in bindings #1501

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 52 additions & 2 deletions bindings_ffi/src/mls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -906,8 +906,11 @@ impl FfiConversations {
};

let convo = if account_addresses.is_empty() {
self.inner_client
.create_group(group_permissions, metadata_options)?
let group = self
.inner_client
.create_group(group_permissions, metadata_options)?;
group.sync().await?;
group
} else {
self.inner_client
.create_group_with_members(&account_addresses, group_permissions, metadata_options)
Expand Down Expand Up @@ -5650,4 +5653,51 @@ mod tests {
FfiReactionSchema::Unicode
));
}

#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
async fn test_update_policies_empty_group() {
let amal = new_test_client().await;
let bola = new_test_client().await;

// Create a group with amal and bola with admin-only permissions
let admin_only_options = FfiCreateGroupOptions {
permissions: Some(FfiGroupPermissionsOptions::AdminOnly),
..Default::default()
};
let amal_group = amal
.conversations()
.create_group(
vec![bola.account_address.clone()],
admin_only_options.clone(),
)
.await
.unwrap();

// Verify we can update the group name without syncing first
amal_group
.update_group_name("New Group Name 1".to_string())
.await
.unwrap();

// Verify the name is updated
amal_group.sync().await.unwrap();
assert_eq!(amal_group.group_name().unwrap(), "New Group Name 1");

// Create a group with just amal
let amal_solo_group = amal
.conversations()
.create_group(vec![], admin_only_options)
.await
.unwrap();

// Verify we can update the group name
amal_solo_group
.update_group_name("New Group Name 2".to_string())
.await
.unwrap();

// Verify the name is updated
amal_solo_group.sync().await.unwrap();
assert_eq!(amal_solo_group.group_name().unwrap(), "New Group Name 2");
}
}
9 changes: 7 additions & 2 deletions bindings_node/src/conversations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,15 @@ impl Conversations {
};

let convo = if account_addresses.is_empty() {
self
let group = self
.inner_client
.create_group(group_permissions, metadata_options)
.map_err(|e| Error::from_reason(format!("ClientError: {}", e)))?
.map_err(|e| Error::from_reason(format!("ClientError: {}", e)))?;
group
.sync()
.await
.map_err(|e| Error::from_reason(format!("ClientError: {}", e)))?;
group
} else {
self
.inner_client
Expand Down
33 changes: 33 additions & 0 deletions bindings_node/test/Conversations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,4 +619,37 @@ describe('Conversations', () => {
await group2.send(encodeTextMessage('gm!'))
expect(group2.consentState()).toBe(ConsentState.Allowed)
})

it('should update group metadata in empty group', async () => {
const user1 = createUser()
const client1 = await createRegisteredClient(user1)

// Create empty group with admin-only permissions
const group = await client1.conversations().createGroup([], {
permissions: GroupPermissionsOptions.AdminOnly,
})
expect(group).toBeDefined()

// Update group name without syncing first
await group.updateGroupName('New Group Name 1')
expect(group.groupName()).toBe('New Group Name 1')

// Verify name persists after sync
await group.sync()
expect(group.groupName()).toBe('New Group Name 1')

// Create another empty group
const soloGroup = await client1.conversations().createGroup([], {
permissions: GroupPermissionsOptions.AdminOnly,
})
expect(soloGroup).toBeDefined()

// Update and verify name
await soloGroup.updateGroupName('New Group Name 2')
expect(soloGroup.groupName()).toBe('New Group Name 2')

// Verify name persists after sync
await soloGroup.sync()
expect(soloGroup.groupName()).toBe('New Group Name 2')
})
})
9 changes: 7 additions & 2 deletions bindings_wasm/src/conversations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,15 @@ impl Conversations {
};

let convo = if account_addresses.is_empty() {
self
let group = self
.inner_client
.create_group(group_permissions, metadata_options)
.map_err(|e| JsError::new(format!("{}", e).as_str()))?
.map_err(|e| JsError::new(format!("{}", e).as_str()))?;
group
.sync()
.await
.map_err(|e| JsError::new(format!("{}", e).as_str()))?;
group
} else {
self
.inner_client
Expand Down
67 changes: 46 additions & 21 deletions xmtp_mls/src/groups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2745,43 +2745,68 @@ pub(crate) mod tests {
#[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))]
async fn test_update_policies_empty_group() {
let amal = ClientBuilder::new_test_client(&generate_local_wallet()).await;
let bola_wallet = generate_local_wallet();
let _bola = ClientBuilder::new_test_client(&bola_wallet).await;

// Create a group and verify it has the default group name
// Create a group with amal and bola
let policy_set = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set());
let amal_group = amal
.create_group(policy_set, GroupMetadataOptions::default())
.create_group_with_members(
&[bola_wallet.get_address()],
policy_set,
GroupMetadataOptions::default(),
)
.await
.unwrap();
amal_group.sync().await.unwrap();

// Verify we can update the group name without syncing first
amal_group
.update_group_name("New Group Name 1".to_string())
.await
.unwrap();

// Verify the name is updated
amal_group.sync().await.unwrap();
let group_mutable_metadata = amal_group
.mutable_metadata(&amal_group.mls_provider().unwrap())
.unwrap();
assert!(group_mutable_metadata.attributes.len().eq(&4));
assert!(group_mutable_metadata
let group_name_1 = group_mutable_metadata
.attributes
.get(&MetadataField::GroupName.to_string())
.unwrap()
.is_empty());
.unwrap();
assert_eq!(group_name_1, "New Group Name 1");

amal_group
.update_permission_policy(
PermissionUpdateType::AddMember,
PermissionPolicyOption::Allow,
None,
)
.await
// Create a group with just amal
let policy_set_2 = Some(PreconfiguredPolicies::AdminsOnly.to_policy_set());
let amal_group_2 = amal
.create_group(policy_set_2, GroupMetadataOptions::default())
.unwrap();

// Update group name
amal_group
.update_group_name("New Group Name 1".to_string())
// Verify empty group fails to update metadata before syncing
amal_group_2
.update_group_name("New Group Name 2".to_string())
.await
.unwrap();
.expect_err("Should fail to update group name before first sync");

amal_group.send_message("hello".as_bytes()).await.unwrap();
// Sync the group
amal_group_2.sync().await.unwrap();

// Verify amal group sees update
amal_group.sync().await.unwrap();
//Verify we can now update the group name
amal_group_2
.update_group_name("New Group Name 2".to_string())
.await
.unwrap();

// Verify the name is updated
amal_group_2.sync().await.unwrap();
let group_mutable_metadata = amal_group_2
.mutable_metadata(&amal_group_2.mls_provider().unwrap())
.unwrap();
let group_name_2 = group_mutable_metadata
.attributes
.get(&MetadataField::GroupName.to_string())
.unwrap();
assert_eq!(group_name_2, "New Group Name 2");
}

#[wasm_bindgen_test(unsupported = tokio::test(flavor = "current_thread"))]
Expand Down
Loading