Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit aba4b05

Browse files
[Email] Add gmail service UT (#458)
* add gmail service test * fix style corp * fix style corp
1 parent d575461 commit aba4b05

29 files changed

+650
-150
lines changed

solutions/Virtual-Assistant/src/csharp/skills/emailskill/Dialogs/Shared/EmailSkillDialog.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,10 +1312,12 @@ protected async Task HandleDialogExceptions(WaterfallStepContext sc, SkillExcept
13121312

13131313
private IDictionary<string, string> AssembleTelemetryData(WaterfallStepContext sc)
13141314
{
1315-
var telemetryData = new Dictionary<string, string>();
1316-
telemetryData.Add("activityId", sc.Context.Activity.Id);
1317-
telemetryData.Add("userId", sc.Context.Activity.From.Id);
1318-
telemetryData.Add("activeDialog", sc.ActiveDialog.ToString());
1315+
var telemetryData = new Dictionary<string, string>
1316+
{
1317+
{ "activityId", sc.Context.Activity.Id },
1318+
{ "userId", sc.Context.Activity.From.Id },
1319+
{ "activeDialog", sc.ActiveDialog.ToString() }
1320+
};
13191321

13201322
return telemetryData;
13211323
}

solutions/Virtual-Assistant/src/csharp/skills/emailskill/ServiceClients/GoogleAPI/GMailService.cs

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Google.Apis.Auth.OAuth2.Responses;
1616
using Google.Apis.Gmail.v1;
1717
using Google.Apis.Gmail.v1.Data;
18+
using Google.Apis.Requests;
1819
using Google.Apis.Services;
1920
using Google.Apis.Util.Store;
2021
using Microsoft.Bot.Solutions.Data;
@@ -31,7 +32,7 @@ namespace EmailSkill
3132
public class GMailService : IMailService
3233
{
3334
private static GmailService service;
34-
private int pageSize;
35+
private readonly int pageSize;
3536
private string pageToken = string.Empty;
3637

3738
/// <summary>
@@ -75,6 +76,49 @@ public static GmailService GetServiceClient(GoogleClient config, string token)
7576
return service;
7677
}
7778

79+
public static string Base64UrlEncode(string text)
80+
{
81+
var textBytes = Encoding.UTF8.GetBytes(text);
82+
83+
var result = System.Convert.ToBase64String(textBytes);
84+
result = result.Split('=')[0]; // Remove any trailing '='s
85+
result = result.Replace('+', '-'); // 62nd char of encoding
86+
result = result.Replace('/', '_'); // 63rd char of encoding
87+
return result;
88+
}
89+
90+
// decode from base64url to utf-8 bytes
91+
public static byte[] Base64UrlDecode(string text)
92+
{
93+
string result = text;
94+
result = result.Replace('-', '+'); // 62nd char of encoding
95+
result = result.Replace('_', '/'); // 63rd char of encoding
96+
97+
// Pad with trailing '='s
98+
switch (result.Length % 4)
99+
{
100+
case 0: break; // No pad chars in this case
101+
case 2: result += "=="; break; // Two pad chars
102+
case 3: result += "="; break; // One pad char
103+
default:
104+
throw new System.Exception(
105+
"Illegal base64url string!");
106+
}
107+
108+
byte[] textBytes = Convert.FromBase64String(result);
109+
return textBytes;
110+
}
111+
112+
// decode to mimeMessage
113+
public static MimeMessage DecodeToMessage(string text)
114+
{
115+
byte[] msg = Base64UrlDecode(text);
116+
MemoryStream mm = new MemoryStream(msg);
117+
MimeKit.MimeMessage mime = MimeKit.MimeMessage.Load(mm);
118+
return mime;
119+
}
120+
121+
/// <inheritdoc/>
78122
public async Task ForwardMessageAsync(string id, string content, List<Recipient> recipients)
79123
{
80124
try
@@ -131,28 +175,33 @@ public async Task ForwardMessageAsync(string id, string content, List<Recipient>
131175
content = quoted.ToString();
132176
}
133177

134-
await service.Users.Messages.Send(
178+
var sendRequest = service.Users.Messages.Send(
135179
new GmailMessage()
136180
{
137181
Raw = Base64UrlEncode(forward.ToString() + content),
138182
ThreadId = threadId,
139-
}, "me").ExecuteAsync();
183+
}, "me");
184+
await ((IClientServiceRequest<GmailMessage>)sendRequest).ExecuteAsync();
140185
}
141186
catch (GoogleApiException ex)
142187
{
143188
throw GoogleClient.HandleGoogleAPIException(ex);
144189
}
145-
}
190+
}
146191

147-
public async Task SendMessageAsync(string content, string subject, List<Recipient> recipients)
192+
public async Task SendMessageAsync(string content, string subject, List<Recipient> recipients)
148193
{
149194
try
150195
{
151196
// get from address
152-
var user = service.Users.GetProfile("me").Execute();
153-
var mess = new MailMessage();
154-
mess.Subject = subject;
155-
mess.From = new MailAddress(user.EmailAddress);
197+
var profileRequest = service.Users.GetProfile("me");
198+
var user = ((IClientServiceRequest<Profile>)profileRequest).Execute();
199+
var mess = new MailMessage
200+
{
201+
Subject = subject,
202+
From = new MailAddress(user.EmailAddress)
203+
};
204+
156205
foreach (var re in recipients)
157206
{
158207
mess.To.Add(new MailAddress(re.EmailAddress.Address));
@@ -164,11 +213,12 @@ public async Task SendMessageAsync(string content, string subject, List<Recipien
164213
mess.AlternateViews.Add(adds);
165214

166215
var mime = MimeMessage.CreateFromMailMessage(mess);
167-
await service.Users.Messages.Send(
216+
var sendRequest = service.Users.Messages.Send(
168217
new GmailMessage()
169-
{
170-
Raw = Base64UrlEncode(mime.ToString()),
171-
}, "me").ExecuteAsync();
218+
{
219+
Raw = Base64UrlEncode(mime.ToString()),
220+
}, "me");
221+
await ((IClientServiceRequest<GmailMessage>)sendRequest).ExecuteAsync();
172222
}
173223
catch (GoogleApiException ex)
174224
{
@@ -238,12 +288,13 @@ public async Task<List<MSMessage>> ReplyToMessageAsync(string id, string content
238288
content = quoted.ToString();
239289
}
240290

241-
await service.Users.Messages.Send(
242-
new GmailMessage()
291+
var sendRequest = service.Users.Messages.Send(
292+
new GmailMessage()
243293
{
244294
Raw = Base64UrlEncode(reply.ToString() + content),
245295
ThreadId = threadId,
246-
}, "me").ExecuteAsync();
296+
}, "me");
297+
await ((IClientServiceRequest<GmailMessage>)sendRequest).ExecuteAsync();
247298
return null;
248299
}
249300
catch (GoogleApiException ex)
@@ -256,7 +307,8 @@ public async Task<List<MSMessage>> GetMyMessagesAsync(DateTime fromTime, DateTim
256307
{
257308
try
258309
{
259-
var user = service.Users.GetProfile("me").Execute();
310+
var profileRequest = service.Users.GetProfile("me");
311+
var user = ((IClientServiceRequest<Profile>)profileRequest).Execute();
260312
var userAddress = user.EmailAddress;
261313

262314
string searchOperation = string.Empty;
@@ -302,7 +354,7 @@ public async Task<List<MSMessage>> GetMyMessagesAsync(DateTime fromTime, DateTim
302354
var tempReq = service.Users.Messages.List("me");
303355
tempReq.MaxResults = skip;
304356
tempReq.Q = searchOperation;
305-
var tempRes = tempReq.Execute();
357+
var tempRes = ((IClientServiceRequest<ListMessagesResponse>)tempReq).Execute();
306358
if (tempRes.NextPageToken != null && tempRes.NextPageToken != string.Empty)
307359
{
308360
this.pageToken = tempRes.NextPageToken;
@@ -316,8 +368,8 @@ public async Task<List<MSMessage>> GetMyMessagesAsync(DateTime fromTime, DateTim
316368
request.PageToken = this.pageToken;
317369
}
318370

319-
ListMessagesResponse response = await request.ExecuteAsync();
320-
List<MSMessage> result = new List<MSMessage>();
371+
var response = await ((IClientServiceRequest<ListMessagesResponse>)request).ExecuteAsync();
372+
var result = new List<MSMessage>();
321373

322374
// response.Messages only have id and threadID
323375
if (response.Messages != null)
@@ -326,7 +378,7 @@ public async Task<List<MSMessage>> GetMyMessagesAsync(DateTime fromTime, DateTim
326378
{
327379
var req = service.Users.Messages.Get("me", temp.Id);
328380
req.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Raw;
329-
return req.ExecuteAsync();
381+
return ((IClientServiceRequest<GmailMessage>)req).ExecuteAsync();
330382
}));
331383
if (messages != null && messages.Length > 0)
332384
{
@@ -379,46 +431,21 @@ public string AppendFilterString(string old, string filterString)
379431
return result;
380432
}
381433

382-
private static string Base64UrlEncode(string text)
383-
{
384-
var textBytes = Encoding.UTF8.GetBytes(text);
385-
return System.Convert.ToBase64String(textBytes)
386-
.Replace('+', '-')
387-
.Replace('/', '_')
388-
.Replace("=", string.Empty);
389-
}
390-
391-
// decode from base64url to utf-8 bytes
392-
private static byte[] Base64UrlDecode(string text)
393-
{
394-
var temp = text.Replace('-', '+')
395-
.Replace('_', '/');
396-
byte[] textBytes = Convert.FromBase64String(temp);
397-
return textBytes; // Encoding.UTF8.GetString(textBytes);
398-
}
399-
400-
// decode to mimeMessage
401-
private static MimeMessage DecodeToMessage(string text)
402-
{
403-
byte[] msg = Base64UrlDecode(text);
404-
MemoryStream mm = new MemoryStream(msg);
405-
MimeKit.MimeMessage mime = MimeKit.MimeMessage.Load(mm);
406-
return mime;
407-
}
408-
409434
private async Task<(MimeMessage, string)> GetMessageById(string id)
410435
{
411436
var request = service.Users.Messages.Get("me", id);
412437
request.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Raw;
413-
var response = await request.ExecuteAsync();
438+
var response = await ((IClientServiceRequest<GmailMessage>)request).ExecuteAsync();
414439
var mime = DecodeToMessage(response.Raw);
415440
return (mime, response.ThreadId);
416441
}
417442

418443
private MSMessage MapMimeMessageToMSMessage(MimeMessage mime)
419444
{
420-
MSMessage message = new MSMessage();
421-
message.ReceivedDateTime = mime.Date;
445+
MSMessage message = new MSMessage
446+
{
447+
ReceivedDateTime = mime.Date
448+
};
422449
if (mime.To != null)
423450
{
424451
var to = new List<Recipient>();

solutions/Virtual-Assistant/src/csharp/skills/emailskill/ServiceClients/GoogleAPI/GooglePeopleService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Google.Apis.Auth.OAuth2.Responses;
1111
using Google.Apis.People.v1;
1212
using Google.Apis.People.v1.Data;
13+
using Google.Apis.Requests;
1314
using Google.Apis.Services;
1415
using Google.Apis.Util.Store;
1516
using Microsoft.Graph;
@@ -78,8 +79,8 @@ public async Task<List<MsPerson>> GetPeopleAsync(string name)
7879
PeopleResource.ConnectionsResource.ListRequest peopleRequest = service.People.Connections.List("people/me");
7980
peopleRequest.RequestMaskIncludeField = "person.emailAddresses,person.names";
8081

81-
ListConnectionsResponse connectionsResponse = await peopleRequest.ExecuteAsync();
82-
IList<GooglePerson> connections = connectionsResponse.Connections;
82+
ListConnectionsResponse connectionsResponse = await ((IClientServiceRequest<ListConnectionsResponse>)peopleRequest).ExecuteAsync();
83+
IList<GooglePerson> connections = connectionsResponse.Connections;
8384

8485
var result = new List<MsPerson>();
8586
if (connections != null && connections.Count > 0)

solutions/Virtual-Assistant/src/csharp/skills/emailskill/ServiceClients/IMailService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ public interface IMailService
4141
/// </summary>
4242
/// <param name="startDateTime">Start date time.</param>
4343
/// <param name="endDateTime">End date time.</param>
44-
/// <param name="isRead">If been read.</param>
44+
/// <param name="getUnRead">If been read.</param>
4545
/// <param name="isImportant">If important.</param>
4646
/// <param name="directlyToMe">If directly to user.</param>
4747
/// <param name="mailAddress">Message coming from address.</param>
4848
/// <param name="skip">Skip message count.</param>
4949
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
50-
Task<List<Message>> GetMyMessagesAsync(DateTime startDateTime, DateTime endDateTime, bool isRead, bool isImportant, bool directlyToMe, string mailAddress, int skip);
50+
Task<List<Message>> GetMyMessagesAsync(DateTime startDateTime, DateTime endDateTime, bool getUnRead, bool isImportant, bool directlyToMe, string mailAddress, int skip);
5151

5252
/// <summary>
5353
/// Delete email.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System.Collections.Generic;
2+
using System.Net.Mail;
3+
using System.Text;
4+
using EmailSkill;
5+
using MimeKit;
6+
using GmailMessage = Google.Apis.Gmail.v1.Data.Message;
7+
8+
namespace EmailSkillTest.API.Fakes
9+
{
10+
public class GmailUtil
11+
{
12+
public static IList<GmailMessage> GetFakeGmailMessageList(int size = 5)
13+
{
14+
var messages = new List<GmailMessage>();
15+
16+
for (int i = 0; i < size; i++)
17+
{
18+
var message = GetFakeGmailMessage(to: "[email protected]" + i);
19+
messages.Add(message);
20+
}
21+
22+
return messages;
23+
}
24+
25+
public static GmailMessage GetFakeGmailMessage(
26+
string from = "[email protected]",
27+
string to = "[email protected]",
28+
string subject = "test subject",
29+
string content = "test content")
30+
{
31+
var mess = new MailMessage
32+
{
33+
Subject = subject,
34+
From = new MailAddress(from)
35+
};
36+
mess.To.Add(new MailAddress(to));
37+
38+
var adds = AlternateView.CreateAlternateViewFromString(content, new System.Net.Mime.ContentType("text/plain"));
39+
adds.ContentType.CharSet = Encoding.UTF8.WebName;
40+
mess.AlternateViews.Add(adds);
41+
42+
var mime = MimeMessage.CreateFromMailMessage(mess);
43+
var gmailMessage = new GmailMessage()
44+
{
45+
Raw = GMailService.Base64UrlEncode(mime.ToString()),
46+
ThreadId = "1"
47+
};
48+
49+
return gmailMessage;
50+
}
51+
}
52+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Google.Apis.Gmail.v1;
2+
using Moq;
3+
using static Google.Apis.Gmail.v1.UsersResource;
4+
using GmailMessage = Google.Apis.Gmail.v1.Data.Message;
5+
6+
namespace EmailSkillTest.API.Fakes
7+
{
8+
public class MockGoogleServiceClient
9+
{
10+
private readonly Mock<GmailService> mockMailService;
11+
private readonly Mock<MessagesResource> mockMessagesResource;
12+
private readonly Mock<UsersResource> mockUsersResource;
13+
14+
public MockGoogleServiceClient()
15+
{
16+
this.mockMailService = new Mock<GmailService>();
17+
this.mockMessagesResource = new Mock<MessagesResource>(mockMailService.Object);
18+
this.mockUsersResource = new Mock<UsersResource>(mockMailService.Object);
19+
20+
this.mockUsersResource.SetupGet(users => users.Messages).Returns(mockMessagesResource.Object);
21+
22+
this.mockUsersResource.Setup(users => users.GetProfile(It.IsAny<string>())).Returns((string userId) =>
23+
{
24+
MockUsersResource.MockGetProfileRequest mockGetProfileRequest = new MockUsersResource.MockGetProfileRequest(this.mockMailService.Object, userId);
25+
return mockGetProfileRequest;
26+
});
27+
28+
this.mockMailService.SetupGet(service => service.Users).Returns(mockUsersResource.Object);
29+
30+
this.mockMessagesResource.Setup(messages => messages.Send(It.IsAny<GmailMessage>(), It.IsAny<string>())).Returns((GmailMessage body, string userId) =>
31+
{
32+
MockMessagesResource.MockSendRequest mockSendRequest = new MockMessagesResource.MockSendRequest(this.mockMailService.Object, body, userId);
33+
return mockSendRequest;
34+
});
35+
36+
this.mockMessagesResource.Setup(messages => messages.Get(It.IsAny<string>(), It.IsAny<string>())).Returns((string userId, string id) =>
37+
{
38+
MockMessagesResource.MockGetRequest mockGetRequest = new MockMessagesResource.MockGetRequest(this.mockMailService.Object, userId, id);
39+
40+
return mockGetRequest;
41+
});
42+
43+
this.mockMessagesResource.Setup(messages => messages.List(It.IsAny<string>())).Returns((string userId) =>
44+
{
45+
MockMessagesResource.MockListRequest mockListRequest = new MockMessagesResource.MockListRequest(this.mockMailService.Object, userId);
46+
47+
return mockListRequest;
48+
});
49+
}
50+
51+
public Mock<GmailService> GetMockGraphServiceClient()
52+
{
53+
return this.mockMailService;
54+
}
55+
}
56+
}

0 commit comments

Comments
 (0)