using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Util.Store;
using Google.Contacts;
using Google.GData.Client;
using Google.GData.Contacts;
using Google.GData.Extensions;
using NodaTime;
using NUnit.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace GoContactSyncMod.UnitTests
{
[TestFixture]
public class GoogleAPITests
{
private static Logger.LogUpdatedHandler _logUpdateHandler = null;
private EventsResource eventsService = null;
private CalendarListEntry primaryCalendar = null;
[OneTimeSetUp]
public void Init()
{
if (_logUpdateHandler == null)
{
_logUpdateHandler = new Logger.LogUpdatedHandler(Logger_LogUpdated);
Logger.LogUpdated += _logUpdateHandler;
}
LoadSettings(out var gmailUsername, out _);
var scopes = new List<string>();
//Contacts-Scope
scopes.Add("https://www.google.com/m8/feeds");
scopes.Add(CalendarService.Scope.Calendar);
UserCredential credential;
var jsonSecrets = Properties.Resources.client_secrets;
//using (var stream = new FileStream(Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(this.GetType()).Location) + "\\client_secrets.json", FileMode.Open, FileAccess.Read))
//using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
//using (var stream = new FileStream(Application.StartupPath + "\\client_secrets.json", FileMode.Open, FileAccess.Read))
using (var stream = new MemoryStream(jsonSecrets))
{
var fDS = new FileDataStore(Logger.AuthFolder, true);
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets, scopes, gmailUsername, CancellationToken.None,
fDS).Result;
var initializer = new Google.Apis.Services.BaseClientService.Initializer
{
HttpClientInitializer = credential
};
var CalendarRequest = new CalendarService(initializer);
//CalendarRequest.setUserCredentials(username, password);
var list = CalendarRequest.CalendarList.List().Execute().Items;
foreach (var calendar in list)
{
if (calendar.Primary != null && calendar.Primary.Value)
{
primaryCalendar = calendar;
break;
}
}
if (primaryCalendar == null)
{
throw new Exception("Primary Calendar not found");
}
//EventQuery query = new EventQuery("https://www.google.com/calendar/feeds/default/private/full");
//ToDo: Upgrade to v3, EventQuery query = new EventQuery("https://www.googleapis.com/calendar/v3/calendars/default/events");
eventsService = CalendarRequest.Events;
}
}
[Test]
public void CreateNewContact()
{
LoadSettings(out var gmailUsername, out _);
ContactsRequest service;
var scopes = new List<string>();
//Contacts-Scope
scopes.Add("https://www.google.com/m8/feeds");
//Calendar-Scope
scopes.Add(CalendarService.Scope.Calendar);
UserCredential credential;
var jsonSecrets = Properties.Resources.client_secrets;
using (var stream = new MemoryStream(jsonSecrets))
{
var fDS = new FileDataStore(Logger.AuthFolder, true);
var clientSecrets = GoogleClientSecrets.Load(stream);
credential = GCSMOAuth2WebAuthorizationBroker.AuthorizeAsync(
clientSecrets.Secrets,
scopes.ToArray(),
gmailUsername,
CancellationToken.None,
fDS).
Result;
var parameters = new OAuth2Parameters
{
ClientId = clientSecrets.Secrets.ClientId,
ClientSecret = clientSecrets.Secrets.ClientSecret,
// Note: AccessToken is valid only for 60 minutes
AccessToken = credential.Token.AccessToken,
RefreshToken = credential.Token.RefreshToken
};
var settings = new RequestSettings("GoContactSyncMod", parameters);
service = new ContactsRequest(settings);
}
#region Delete previously created test contact.
var query = new ContactsQuery(ContactsQuery.CreateContactsUri("default"))
{
NumberToRetrieve = 500
};
var feed = service.Get<Contact>(query);
Logger.Log("Loaded Google contacts", EventType.Information);
foreach (var entry in feed.Entries)
{
if (entry.PrimaryEmail != null && entry.PrimaryEmail.Address == "johndoe@example.com")
{
service.Delete(entry);
Logger.Log("Deleted Google contact", EventType.Information);
//break;
}
}
#endregion
var newEntry = new Contact
{
Title = "John Doe"
};
var primaryEmail = new EMail("johndoe@example.com")
{
Primary = true,
Rel = ContactsRelationships.IsWork
};
newEntry.Emails.Add(primaryEmail);
var phoneNumber = new PhoneNumber("555-555-5551")
{
Primary = true,
Rel = ContactsRelationships.IsMobile
};
newEntry.Phonenumbers.Add(phoneNumber);
var postalAddress = new StructuredPostalAddress
{
Street = "123 somewhere lane",
Primary = true,
Rel = ContactsRelationships.IsHome
};
newEntry.PostalAddresses.Add(postalAddress);
newEntry.Content = "Who is this guy?";
var feedUri = new Uri(ContactsQuery.CreateContactsUri("default"));
var createdEntry = service.Insert(feedUri, newEntry);
Logger.Log("Created Google contact", EventType.Information);
Assert.IsNotNull(createdEntry.ContactEntry.Id.Uri);
_ = service.Update(createdEntry);
Logger.Log("Updated Google contact", EventType.Information);
//delete test contacts
service.Delete(createdEntry);
Logger.Log("Deleted Google contact", EventType.Information);
}
[Test]
public void CreateNewAppointment()
{
#region Delete previously created test contact.
var query = eventsService.List(primaryCalendar.Id);
query.MaxResults = 500;
query.TimeMin = DateTime.Now.AddDays(-10);
query.TimeMax = DateTime.Now.AddDays(10);
//query.Q = "GCSM Test Appointment";
var feed = query.Execute();
Logger.Log("Loaded Google appointments", EventType.Information);
foreach (var entry in feed.Items)
{
if (entry.Summary != null && entry.Summary.Contains("GCSM Test Appointment") && !entry.Status.Equals("cancelled"))
{
Logger.Log("Deleting Google appointment:" + entry.Summary + " - " + entry.Start.DateTime.ToString(), EventType.Information);
eventsService.Delete(primaryCalendar.Id, entry.Id);
Logger.Log("Deleted Google appointment", EventType.Information);
//break;
}
}
#endregion
var newEntry = Factory.NewEvent();
newEntry.Summary = "GCSM Test Appointment";
newEntry.Start.DateTime = DateTime.Now;
newEntry.End.DateTime = DateTime.Now;
var createdEntry = eventsService.Insert(newEntry, primaryCalendar.Id).Execute();
Logger.Log("Created Google appointment", EventType.Information);
Assert.IsNotNull(createdEntry.Id);
var updatedEntry = eventsService.Update(createdEntry, primaryCalendar.Id, createdEntry.Id).Execute();
Logger.Log("Updated Google appointment", EventType.Information);
//delete test contacts
eventsService.Delete(primaryCalendar.Id, updatedEntry.Id).Execute();
Logger.Log("Deleted Google appointment", EventType.Information);
}
[Test]
public void Test_OldRecurringAppointment()
{
#region Delete previously created test contact.
var query = eventsService.List(primaryCalendar.Id);
query.MaxResults = 500;
query.TimeMin = DateTime.Now.AddDays(-10);
query.TimeMax = DateTime.Now.AddDays(10);
//query.Q = "GCSM Test Appointment";
var feed = query.Execute();
Logger.Log("Loaded Google appointments", EventType.Information);
foreach (var entry in feed.Items)
{
if (entry.Summary != null && entry.Summary.Contains("GCSM Test Appointment") && !entry.Status.Equals("cancelled"))
{
Logger.Log("Deleting Google appointment:" + entry.Summary + " - " + entry.Start.DateTime.ToString(), EventType.Information);
eventsService.Delete(primaryCalendar.Id, entry.Id);
Logger.Log("Deleted Google appointment", EventType.Information);
//break;
}
}
#endregion
var zone = DateTimeZoneProviders.Tzdb["Europe/Warsaw"];
var e1_start = new LocalDateTime(1970, 10, 14, 10, 0, 0);
var e1_start_zoned = e1_start.InZoneLeniently(zone);
var e1_start_utc = e1_start_zoned.ToDateTimeUtc();
_ = new LocalDateTime(1970, 10, 14, 11, 0, 0);
_ = e1_start.InZoneLeniently(zone);
var e1_end_utc = e1_start_zoned.ToDateTimeUtc();
var s = new EventDateTime
{
DateTime = e1_start_utc,
TimeZone = "Europe/Warsaw"
};
var e = new EventDateTime
{
DateTime = e1_end_utc,
TimeZone = "Europe/Warsaw"
};
var e1 = new Google.Apis.Calendar.v3.Data.Event()
{
Summary = "Birthday 1",
Start = s,
End = e,
Recurrence = new string[] { "RRULE:FREQ=YEARLY;BYMONTHDAY=14;BYMONTH=10" }
};
Assert.AreEqual("1970-10-14T09:00:00.000Z", e1.Start.DateTimeRaw);
var c1 = eventsService.Insert(e1, primaryCalendar.Id).Execute();
Assert.AreEqual("1970-10-14T10:00:00+01:00", c1.Start.DateTimeRaw);
var e2_start = new LocalDateTime(2000, 10, 14, 10, 0, 0);
var e2_start_zoned = e2_start.InZoneLeniently(zone);
var e2_start_utc = e2_start_zoned.ToDateTimeUtc();
_ = new LocalDateTime(2000, 10, 14, 11, 0, 0);
_ = e2_start.InZoneLeniently(zone);
var e2_end_utc = e2_start_zoned.ToDateTimeUtc();
var ss = new EventDateTime
{
DateTime = e2_start_utc,
TimeZone = "Europe/Warsaw"
};
var ee = new EventDateTime
{
DateTime = e2_end_utc,
TimeZone = "Europe/Warsaw"
};
var e2 = new Google.Apis.Calendar.v3.Data.Event()
{
Summary = "Birthday 2",
Start = ss,
End = ee,
Recurrence = new string[] { "RRULE:FREQ=YEARLY;BYMONTHDAY=14;BYMONTH=10" }
};
Assert.AreEqual("2000-10-14T08:00:00.000Z", e2.Start.DateTimeRaw);
var c2 = eventsService.Insert(e2, primaryCalendar.Id).Execute();
Assert.AreEqual("2000-10-14T10:00:00+02:00", c2.Start.DateTimeRaw);
Logger.Log("Created Google appointment", EventType.Information);
Assert.IsNotNull(c1.Id);
//delete test contacts
eventsService.Delete(primaryCalendar.Id, c1.Id).Execute();
eventsService.Delete(primaryCalendar.Id, c2.Id).Execute();
Logger.Log("Deleted Google appointment", EventType.Information);
}
[Test]
public void Test_RetrieveRecurrenceInstance()
{
var e = new Google.Apis.Calendar.v3.Data.Event()
{
Summary = "AN_OUTLOOK_TEST_APPOINTMENT",
Start = new EventDateTime()
{
DateTime = new DateTime(2020, 6, 3, 15, 0, 0),
TimeZone = "Europe/Warsaw"
},
End = new EventDateTime()
{
DateTime = new DateTime(2020, 6, 3, 16, 0, 0),
TimeZone = "Europe/Warsaw"
},
Recurrence = new string[] { "RRULE:FREQ=WEEKLY;UNTIL=20200625;BYDAY=WE" }
};
e = eventsService.Insert(e, primaryCalendar.Id).Execute();
Assert.IsNotNull(e.Id);
var r = eventsService.Instances(primaryCalendar.Id, e.Id);
var dt = new DateTime(2020, 6, 10, 13, 0, 0, DateTimeKind.Utc);
var s = dt.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:sszzz");
Assert.AreEqual("2020-06-10T15:00:00+02:00", s);
r.OriginalStart = "2020-06-10T15:00:00+02:00";
var instances = r.Execute();
Assert.IsNotNull(instances);
Assert.AreEqual(1, instances.Items.Count);
//delete test contacts
eventsService.Delete(primaryCalendar.Id, e.Id).Execute();
Logger.Log("Deleted Google appointment", EventType.Information);
}
[Test]
public void CreateContactWithLargeNotes()
{
LoadSettings(out var gmailUsername, out _);
ContactsRequest service;
var scopes = new List<string>();
//Contacts-Scope
scopes.Add("https://www.google.com/m8/feeds");
//Calendar-Scope
scopes.Add(CalendarService.Scope.Calendar);
UserCredential credential;
var jsonSecrets = Properties.Resources.client_secrets;
using (var stream = new MemoryStream(jsonSecrets))
{
var fDS = new FileDataStore(Logger.AuthFolder, true);
var clientSecrets = GoogleClientSecrets.Load(stream);
credential = GCSMOAuth2WebAuthorizationBroker.AuthorizeAsync(
clientSecrets.Secrets,
scopes.ToArray(),
gmailUsername,
CancellationToken.None,
fDS).
Result;
var parameters = new OAuth2Parameters
{
ClientId = clientSecrets.Secrets.ClientId,
ClientSecret = clientSecrets.Secrets.ClientSecret,
// Note: AccessToken is valid only for 60 minutes
AccessToken = credential.Token.AccessToken,
RefreshToken = credential.Token.RefreshToken
};
var settings = new RequestSettings("GoContactSyncMod", parameters);
service = new ContactsRequest(settings);
}
#region Delete previously created test contact.
var query = new ContactsQuery(ContactsQuery.CreateContactsUri("default"))
{
NumberToRetrieve = 500
};
var feed = service.Get<Contact>(query);
Logger.Log("Loaded Google contacts", EventType.Information);
foreach (var entry in feed.Entries)
{
if (entry.PrimaryEmail != null && entry.PrimaryEmail.Address == "johndoe@example.com")
{
service.Delete(entry);
Logger.Log("Deleted Google contact", EventType.Information);
//break;
}
}
#endregion
var newEntry = new Contact
{
Title = "John Doe"
};
var primaryEmail = new EMail("johndoe@example.com")
{
Primary = true,
Rel = ContactsRelationships.IsWork
};
newEntry.Emails.Add(primaryEmail);
var phoneNumber = new PhoneNumber("555-555-5551")
{
Primary = true,
Rel = ContactsRelationships.IsMobile
};
newEntry.Phonenumbers.Add(phoneNumber);
var postalAddress = new StructuredPostalAddress
{
Street = "123 somewhere lane",
Primary = true,
Rel = ContactsRelationships.IsHome
};
newEntry.PostalAddresses.Add(postalAddress);
newEntry.Content = new string('*', 150000);
var feedUri = new Uri(ContactsQuery.CreateContactsUri("default"));
try
{
var createdEntry = service.Insert(feedUri, newEntry);
Logger.Log("Created Google contact", EventType.Information);
Assert.IsNotNull(createdEntry.ContactEntry.Id.Uri);
_ = service.Update(createdEntry);
Logger.Log("Updated Google contact", EventType.Information);
//delete test contacts
service.Delete(createdEntry);
}
catch (GDataRequestException ex) when (ex.ResponseString.Equals("Request data is too large."))
{
Logger.Log(ex, EventType.Information);
}
Logger.Log("Deleted Google contact", EventType.Information);
}
internal static void LoadSettings(out string gmailUsername, out string syncProfile, out string syncContactsFolder, out string syncAppointmentsFolder)
{
var regKeyAppRoot = LoadSettings(out gmailUsername, out syncProfile);
syncContactsFolder = "";
syncAppointmentsFolder = "";
Synchronizer.SyncAppointmentsGoogleFolder = "";
//First, check if there is a folder called GCSMTestContacts available, if yes, use them
var outlookContactFolders = new ArrayList();
var outlookAppointmentFolders = new ArrayList();
var folders = Synchronizer.OutlookNameSpace.Folders;
foreach (Microsoft.Office.Interop.Outlook.Folder folder in folders)
{
try
{
SettingsForm.GetOutlookMAPIFolders(outlookContactFolders, outlookAppointmentFolders, folder);
}
catch (Exception e)
{
Logger.Log("Error getting available Outlook folders: " + e.Message, EventType.Warning);
}
}
foreach (OutlookFolder folder in outlookContactFolders)
{
if (folder.FolderName.ToUpper().Contains("GCSMTestContacts".ToUpper()))
{
Logger.Log("Uses Test folder: " + folder.DisplayName, EventType.Information);
syncContactsFolder = folder.FolderID;
break;
}
}
foreach (OutlookFolder folder in outlookAppointmentFolders)
{
if (folder.FolderName.ToUpper().Contains("GCSMTestAppointments".ToUpper()))
{
Logger.Log("Uses Test folder: " + folder.DisplayName, EventType.Information);
syncAppointmentsFolder = folder.FolderID;
break;
}
}
if (string.IsNullOrEmpty(syncContactsFolder))
{
if (regKeyAppRoot.GetValue("SyncContactsFolder") != null)
{
syncContactsFolder = regKeyAppRoot.GetValue("SyncContactsFolder") as string;
}
}
if (string.IsNullOrEmpty(syncAppointmentsFolder))
{
if (regKeyAppRoot.GetValue("SyncAppointmentsFolder") != null)
{
syncAppointmentsFolder = regKeyAppRoot.GetValue("SyncAppointmentsFolder") as string;
}
}
if (string.IsNullOrEmpty(Synchronizer.SyncAppointmentsGoogleFolder))
{
if (regKeyAppRoot.GetValue("SyncAppointmentsGoogleFolder") != null)
{
Synchronizer.SyncAppointmentsGoogleFolder = regKeyAppRoot.GetValue("SyncAppointmentsGoogeFolder") as string;
}
}
}
private static Microsoft.Win32.RegistryKey LoadSettings(out string gmailUsername, out string syncProfile)
{
//sync.LoginToGoogle(ConfigurationManager.AppSettings["Gmail.Username"], ConfigurationManager.AppSettings["Gmail.Password"]);
//ToDo: Reading the username and config from the App.Config file doesn't work. If it works, consider special characters like & = & in the XML file
//ToDo: Maybe add a common Test account to the App.config and read it from there, encrypt the password
//For now, read the userName from the Registry (same settings as for GoogleContactsSync Application
gmailUsername = "";
const string appRootKey = SettingsForm.AppRootKey;
var regKeyAppRoot = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(appRootKey);
syncProfile = "Default Profile";
if (regKeyAppRoot.GetValue("SyncProfile") != null)
{
syncProfile = regKeyAppRoot.GetValue("SyncProfile") as string;
}
regKeyAppRoot = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(appRootKey + (syncProfile != null ? ('\\' + syncProfile) : ""));
if (regKeyAppRoot.GetValue("Username") != null)
{
gmailUsername = regKeyAppRoot.GetValue("Username") as string;
}
return regKeyAppRoot;
}
private void Logger_LogUpdated(string message)
{
Console.WriteLine(message);
}
}
}