package network_test import ( "context" "os" "testing" "github.com/flowy-live/llink/internal/network" "github.com/flowy-live/llink/internal/testhelper" "github.com/jackc/pgx/v5/pgxpool" "github.com/stretchr/testify/assert" ) var dbPool *pgxpool.Pool func TestMain(m *testing.M) { dbPool = testhelper.SetupTestDB() defer testhelper.TeardownTestDB() ret := m.Run() os.Exit(ret) } func TestNetworkService(t *testing.T) { ctx := context.Background() svc := network.NewService(dbPool) adminHumanId := "human_admin123" member1HumanId := "human_member1abc" member2HumanId := "human_member2def" strangerHumanId := "human_stranger789" // Test Create createdNetwork, err := svc.Create(ctx, "Test Network", adminHumanId) assert.NoError(t, err) assert.NotEmpty(t, createdNetwork.ID) assert.Equal(t, "Test Network", createdNetwork.Name) assert.Equal(t, adminHumanId, createdNetwork.AdminHumanId) assert.NotZero(t, createdNetwork.CreatedAt) // Test GetByID foundNetwork, err := svc.GetByID(ctx, createdNetwork.ID) assert.NoError(t, err) assert.Equal(t, createdNetwork.ID, foundNetwork.ID) assert.Equal(t, createdNetwork.Name, foundNetwork.Name) assert.Equal(t, createdNetwork.AdminHumanId, foundNetwork.AdminHumanId) // Test GetByID with non-existent id _, err = svc.GetByID(ctx, "network_nonexistent") assert.Error(t, err) assert.ErrorIs(t, err, network.ErrNotFound) // Test SetName err = svc.SetName(ctx, createdNetwork.ID, "Updated Network Name") assert.NoError(t, err) // Verify name was updated updatedNetwork, err := svc.GetByID(ctx, createdNetwork.ID) assert.NoError(t, err) assert.Equal(t, "Updated Network Name", updatedNetwork.Name) // Test SetName with non-existent id err = svc.SetName(ctx, "network_nonexistent", "New Name") assert.Error(t, err) assert.ErrorIs(t, err, network.ErrNotFound) // Test AddMembers err = svc.AddMembers(ctx, createdNetwork.ID, []string{member1HumanId, member2HumanId}) assert.NoError(t, err) // Test ListForHuman - should find network for admin networks, err := svc.ListForHuman(ctx, adminHumanId) assert.NoError(t, err) assert.Len(t, networks, 1) assert.Equal(t, createdNetwork.ID, networks[0].ID) // Test ListForHuman - should find network for member networks, err = svc.ListForHuman(ctx, member1HumanId) assert.NoError(t, err) assert.Len(t, networks, 1) assert.Equal(t, createdNetwork.ID, networks[0].ID) // Test ListForHuman - should return empty for non-member networks, err = svc.ListForHuman(ctx, strangerHumanId) assert.NoError(t, err) assert.Len(t, networks, 0) // Test RemoveMember err = svc.RemoveMember(ctx, createdNetwork.ID, member1HumanId) assert.NoError(t, err) // Verify member was removed networks, err = svc.ListForHuman(ctx, member1HumanId) assert.NoError(t, err) assert.Len(t, networks, 0) // member2 should still have access networks, err = svc.ListForHuman(ctx, member2HumanId) assert.NoError(t, err) assert.Len(t, networks, 1) // Create another network and verify ListForHuman returns multiple network2, err := svc.Create(ctx, "Second Network", member2HumanId) assert.NoError(t, err) networks, err = svc.ListForHuman(ctx, member2HumanId) assert.NoError(t, err) assert.Len(t, networks, 2) // Verify both networks are returned networkIDs := []string{networks[0].ID, networks[1].ID} assert.Contains(t, networkIDs, createdNetwork.ID) assert.Contains(t, networkIDs, network2.ID) } func TestNetworkInvitations(t *testing.T) { ctx := context.Background() svc := network.NewService(dbPool) adminHumanId := "human_invtest_admin" inviteeEmail := "invitee@example.com" inviteeHumanId := "human_invitee123" // Create a network net, err := svc.Create(ctx, "Invitation Test Network", adminHumanId) assert.NoError(t, err) // Invite by email err = svc.InviteByEmail(ctx, net.ID, []string{inviteeEmail}) assert.NoError(t, err) // List invitations for email invitations, err := svc.ListInvitationsForEmail(ctx, inviteeEmail) assert.NoError(t, err) assert.Len(t, invitations, 1) assert.Equal(t, net.ID, invitations[0].NetworkID) assert.Equal(t, inviteeEmail, invitations[0].Email) // List invitations for network invitations, err = svc.ListInvitationsForNetwork(ctx, net.ID) assert.NoError(t, err) assert.Len(t, invitations, 1) // Duplicate invite is idempotent err = svc.InviteByEmail(ctx, net.ID, []string{inviteeEmail}) assert.NoError(t, err) invitations, err = svc.ListInvitationsForNetwork(ctx, net.ID) assert.NoError(t, err) assert.Len(t, invitations, 1) // Accept invitation err = svc.AcceptInvitation(ctx, net.ID, inviteeEmail, inviteeHumanId) assert.NoError(t, err) // Invitation should be removed invitations, err = svc.ListInvitationsForEmail(ctx, inviteeEmail) assert.NoError(t, err) assert.Len(t, invitations, 0) // Human should now be a member isMember, err := svc.IsMember(ctx, net.ID, inviteeHumanId) assert.NoError(t, err) assert.True(t, isMember) // Test revoke invitation revokeEmail := "revokee@example.com" err = svc.InviteByEmail(ctx, net.ID, []string{revokeEmail}) assert.NoError(t, err) err = svc.RevokeInvitation(ctx, net.ID, revokeEmail) assert.NoError(t, err) invitations, err = svc.ListInvitationsForEmail(ctx, revokeEmail) assert.NoError(t, err) assert.Len(t, invitations, 0) }