public void SplitsAndJoinsEmpty()
        {
            var initial = new GroupMembership()
            {
                Destination = new AzureADGroup {
                    ObjectId = Guid.NewGuid()
                },
                SyncJobPartitionKey = Guid.NewGuid().ToString(),
                SyncJobRowKey       = Guid.NewGuid().ToString(),
            };

            var split = initial.Split();

            Assert.AreEqual(1, split.Length);
            Assert.AreEqual(0, split.Single().SourceMembers.Count);
            Assert.AreEqual(initial.Destination, split.Single().Destination);
            Assert.AreEqual(initial.SyncJobRowKey, split.Single().SyncJobRowKey);
            Assert.AreEqual(initial.SyncJobPartitionKey, split.Single().SyncJobPartitionKey);
            Assert.IsTrue(split.Single().IsLastMessage);

            var rejoined = GroupMembership.Merge(split);

            Assert.AreEqual(0, rejoined.SourceMembers.Count);
            Assert.AreEqual(initial.Destination, rejoined.Destination);
            Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey);
            Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey);
            CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers);
        }
Example #2
0
        public void SplitsAndJoins()
        {
            var initial = MockGroupMembershipHelper.MockGroupMembership();
            var split   = initial.Split();

            Assert.AreEqual((UserCount / ChunkSize) + 1, split.Length);

            foreach (var chunk in split)
            {
                Assert.AreEqual(initial.Sources, chunk.Sources);
                Assert.AreEqual(initial.Destination, chunk.Destination);
                Assert.AreEqual(initial.SyncJobRowKey, chunk.SyncJobRowKey);
                Assert.AreEqual(initial.SyncJobPartitionKey, chunk.SyncJobPartitionKey);
                Assert.IsFalse(chunk.Errored);
            }

            foreach (var nonlastChunk in split.Take(split.Length - 1))
            {
                Assert.IsFalse(nonlastChunk.IsLastMessage);
                Assert.AreEqual(ChunkSize, nonlastChunk.SourceMembers.Count);
            }

            Assert.IsTrue(split.Last().IsLastMessage);
            Assert.AreEqual(UserCount % ChunkSize, split.Last().SourceMembers.Count);

            var rejoined = GroupMembership.Merge(split);

            Assert.AreEqual(initial.Sources, rejoined.Sources);
            Assert.AreEqual(initial.Destination, rejoined.Destination);
            Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey);
            Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey);
            CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers);
            Assert.IsFalse(rejoined.Errored);
        }
        public void RoundTripSerialization()
        {
            var initial = MockGroupMembershipHelper.MockGroupMembership();

            var split = JsonConvert.DeserializeObject <GroupMembership[]>(JsonConvert.SerializeObject(initial.Split()));

            Assert.AreEqual((UserCount / ChunkSize) + 1, split.Length);

            foreach (var chunk in split)
            {
                Assert.AreEqual(initial.Destination, chunk.Destination);
                Assert.AreEqual(initial.SyncJobRowKey, chunk.SyncJobRowKey);
                Assert.AreEqual(initial.SyncJobPartitionKey, chunk.SyncJobPartitionKey);
            }

            foreach (var nonlastChunk in split.Take(split.Length - 1))
            {
                Assert.IsFalse(nonlastChunk.IsLastMessage);
                Assert.AreEqual(ChunkSize, nonlastChunk.SourceMembers.Count);
            }

            Assert.IsTrue(split.Last().IsLastMessage);
            Assert.AreEqual(UserCount % ChunkSize, split.Last().SourceMembers.Count);

            var rejoined = GroupMembership.Merge(split);

            Assert.AreEqual(initial.Destination, rejoined.Destination);
            Assert.AreEqual(initial.SyncJobRowKey, rejoined.SyncJobRowKey);
            Assert.AreEqual(initial.SyncJobPartitionKey, rejoined.SyncJobPartitionKey);
            CollectionAssert.AreEqual(initial.SourceMembers, rejoined.SourceMembers);
        }
        public async Task HandleNewMessage(GroupMembershipMessage body, IMessageSession messageSession)
        {
            var sessionId = messageSession.SessionId;

            _receivedMessages.AddOrUpdate(sessionId, new List <GroupMembershipMessage> {
                body
            }, (key, messages) => {
                messages.Add(body); return(messages);
            });

            //Console.WriteLine($"Session {sessionId} got {body.Body.SourceMembers.Count} users.");
            if (body.Body.IsLastMessage)
            {
                if (!_receivedMessages.TryRemove(sessionId, out var allReceivedMessages))
                {
                    // someone else got to it first. shouldn't happen, but it's good to be prepared.
                    return;
                }

                // remove this message-renewing logic once we can verify that the new, longer message leases work.
                var source            = new CancellationTokenSource();
                var cancellationToken = source.Token;
                var renew             = RenewMessages(messageSession, allReceivedMessages, cancellationToken);

                var received = GroupMembership.Merge(allReceivedMessages.Select(x => x.Body));

                try
                {
                    await _graphUpdater.CalculateDifference(received);

                    // If it succeeded, complete all the messages and close the session
                    await messageSession.CompleteAsync(allReceivedMessages.Select(x => x.LockToken));

                    await messageSession.CloseAsync();
                }
                finally
                {
                    source.Cancel();
                }
            }
        }
Example #5
0
        public async Task <GroupMembershipMessageResponse> HandleNewMessageAsync(GroupMembershipMessage body, string messageSessionId)
        {
            if (body.IsCancelationMessage)
            {
                _receivedMessages.TryRemove(messageSessionId, out _);
                return(new GroupMembershipMessageResponse());
            }

            _loggingRepository.SyncJobProperties = new Dictionary <string, string>()
            {
                { "LockToken", body.LockToken }, { "RowKey", body.Body.SyncJobRowKey }, { "PartitionKey", body.Body.SyncJobPartitionKey }, { "TargetOfficeGroupId", body.Body.Destination.ObjectId.ToString() }
            };

            var receivedSoFar = _receivedMessages.AddOrUpdate(messageSessionId, new List <GroupMembershipMessage> {
                body
            }, (key, messages) =>
            {
                messages.Add(body); return(messages);
            });

            var handleNewMessageResponse = new GroupMembershipMessageResponse()
            {
                ShouldCompleteMessage = false
            };

            await _loggingRepository.LogMessageAsync(new LogMessage
            {
                RunId   = body.Body.RunId,
                Message = $"Got a message in {nameof(MessageCollector)}. " +
                          $"The message we just received has {body.Body.SourceMembers.Count} users and is {(body.Body.IsLastMessage ? "" : "not ")}the last message in its session. " +
                          $"There are currently {_receivedMessages.Count} sessions in flight. " +
                          $"The current session, the one with ID {messageSessionId}, has {receivedSoFar.Count} messages with {receivedSoFar.Sum(x => x.Body.SourceMembers.Count)} users in total."
            });

            if (body.Body.IsLastMessage)
            {
                if (!_receivedMessages.TryRemove(messageSessionId, out var allReceivedMessages))
                {
                    // someone else got to it first. shouldn't happen, but it's good to be prepared.
                    return(handleNewMessageResponse);
                }

                var received = GroupMembership.Merge(allReceivedMessages.Select(x => x.Body));

                await _loggingRepository.LogMessageAsync(new LogMessage
                {
                    RunId   = body.Body.RunId,
                    Message = $"This message completed the session, so I'm going to sync {received.SourceMembers.Count} users."
                });

                handleNewMessageResponse.CompletedGroupMembershipMessages = allReceivedMessages;
                handleNewMessageResponse.ShouldCompleteMessage            = true;

                return(handleNewMessageResponse);
            }
            else
            {
                await _loggingRepository.LogMessageAsync(new LogMessage
                {
                    RunId   = body.Body.RunId,
                    Message = "This is not the last message, so not doing anything right now."
                });
            }

            _loggingRepository.SyncJobProperties = null;
            return(handleNewMessageResponse);
        }