public List <PluginLoader.LoadedPlugin> LoadPlugins() { RemoveExtractedPluginFolders(); var pluginFiles = Root .GetFiles("*.plugin") .Select(fi => fi.FullName) .ToList(); if (!pluginFiles.Any()) { throw new ExpectedException($"You need to have at least one local *.plugin file at '{Root.FullName}'"); } var loadedPlugins = new PluginLoader { Log = Log4NetLogger.Create(Log), Verbose = Verbose } .LoadPlugins(pluginFiles); var jsonPlugin = loadedPlugins .FirstOrDefault(lp => IsJsonPlugin(lp.Manifest)); if (jsonPlugin != null) { var result = AssemblyQualifiedNameParser.Parse(jsonPlugin.Manifest.AssemblyQualifiedTypeName); JsonPluginVersion = AquariusServerVersion.Create(result.Version); JsonPluginPath = jsonPlugin.Path; } return(loadedPlugins); }
private void ThrowIfJsonPluginNotInstalled() { var serverPlugin = GetServerPlugin(LocalPluginLoader.IsJsonPlugin); var serverPluginVersion = serverPlugin != null ? AquariusServerVersion.Create(PluginLoader.GetPluginVersion(serverPlugin.AssemblyQualifiedTypeName)) : null; if (JsonPluginVersion == null && serverPluginVersion != null) { // There is no local Json plugin to deploy, so assume the server plugin will be good enough return; } if (serverPlugin == null) { InstallJsonPlugin(); return; } if (!serverPluginVersion?.IsLessThan(JsonPluginVersion) ?? false) { // The server JSON plugin is newer, so keep it EnableJsonPlugin(serverPlugin); return; } ReplaceJsonPlugin(serverPlugin); }
public void GetAquariusServerVersion_WithOverrideHostname_ReportsOverrideValueWithoutProbingServer() { var expectedMockVersion = AquariusServerVersion.Create("3.2.1.0"); var expectedOverrideVersion = AquariusServerVersion.Create("16.1.23"); expectedMockVersion.IsLessThan(expectedOverrideVersion).ShouldBeEquivalentTo(true, "Invalid test data"); var mockHostname = "server1"; var overrideHostname = "10.0.0.14"; SetupMockToReturnApiVersion(expectedMockVersion.ToString()); var overrideSetting = string.Format("server3=5.4 ; {0} = {1}", overrideHostname, expectedOverrideVersion); overrideSetting.Contains(mockHostname).ShouldBeEquivalentTo(false, "Invalid test data"); overrideSetting.Contains(expectedMockVersion.ToString()).ShouldBeEquivalentTo(false, "Invalid test data"); var detector = CreateDetector(); detector.SetOverrides(overrideSetting); var mockVersion = detector.GetAquariusServerVersion(mockHostname); var overrideVersion = detector.GetAquariusServerVersion(overrideHostname); mockVersion.ToString().ShouldBeEquivalentTo(expectedMockVersion.ToString()); overrideVersion.ToString().ShouldBeEquivalentTo(expectedOverrideVersion.ToString()); AssertServiceClientCallsReceived(1); }
public void IsDeveloperBuild_DetectsCorrectly(string reason, string versionText, bool expected) { var version = AquariusServerVersion.Create(versionText); var actual = version.IsDeveloperBuild(); actual.ShouldBeEquivalentTo(expected, reason); }
public void Dispose_With3xConnection_DoesNotCallDeleteSession() { _client.ServerVersion = AquariusServerVersion.Create("3.10"); _client.Dispose(); AssertExpectedDeleteSessionRequests(0); }
private SamplesClient(IServiceClient client, string apiToken) { SetupServiceStack(); _client = client; Client.AddHeader(AuthorizationHeaderKey, $"token {apiToken}"); ServerVersion = GetServerVersion(); Log.Info($"Connected to {GetBaseUri()} ({ServerVersion}) ..."); }
private SosClient(string hostUrl, string username, string password, AquariusServerVersion sosServerVersion) { SosServerVersion = sosServerVersion; HostUrl = hostUrl.TrimEnd('/'); Username = username; Password = password; AdaptToSosVersion(); ConfigureJsonOnce(); }
public void ToString_SanitizesMajorVersion(string reason, string apiVersion, string expected) { var version = AquariusServerVersion.Create(apiVersion); var actual = version.ToString(); actual.ShouldBeEquivalentTo(expected, reason); var version2 = AquariusServerVersion.Create(expected); var actualCompare = version.Compare(version2); actualCompare.ShouldBeEquivalentTo(0, "Equivalent version.ToString() should also compare equally: {0}", reason); }
private string InstallPlugin(FileInfo archiveInfo) { using (var archive = LoadPluginArchive(archiveInfo.FullName)) { var manifestEntry = archive.Entries.FirstOrDefault(e => e.FullName.Equals(ManifestFile, StringComparison.InvariantCultureIgnoreCase)); if (manifestEntry == null) { throw new Exception($"Invalid plugin bundle. No manifest found."); } var plugin = LoadPluginFromManifest(manifestEntry); var otherEntries = archive .Entries .Where(e => !ExcludedFromExtraction.Contains(e.FullName)) .ToList(); if (!otherEntries.Any()) { throw new Exception($"Invalid plugin bundle. No file entries found to install."); } if (IsJsonPlugin(plugin)) { JsonPluginPath = archiveInfo.FullName; JsonPluginVersion = AquariusServerVersion.Create(PluginLoader.GetPluginVersion(plugin.AssemblyQualifiedTypeName)); } var pluginFolder = new DirectoryInfo(Path.Combine(Root.FullName, plugin.PluginFolderName)); if (!pluginFolder.Exists || pluginFolder.LastWriteTimeUtc < archiveInfo.LastWriteTimeUtc) { ExtractLocalPlugin(pluginFolder, otherEntries); } return(pluginFolder.FullName); } }
public void Compare_VersionsCompareAsExpected(string reason, string versionText1, string versionText2, bool expectedIs1LessThan2, int expectedCompare1With2) { expectedIs1LessThan2.ShouldBeEquivalentTo(expectedCompare1With2 < 0, "Test expectations are not self-consistent"); var version1 = AquariusServerVersion.Create(versionText1); var version2 = AquariusServerVersion.Create(versionText2); var actualIs1LessThan2 = version1.IsLessThan(version2); actualIs1LessThan2.ShouldBeEquivalentTo(expectedIs1LessThan2, reason); var actualCompare1With2 = version1.Compare(version2); actualCompare1With2.ShouldBeEquivalentTo(expectedCompare1With2, reason); if (expectedIs1LessThan2) { var actualCompare2With1 = version2.Compare(version1); actualCompare2With1.ShouldBeEquivalentTo(1, "ver1 < ver2 should imply that ver2 > ver1"); } }
private AquariusServerVersion GetServerVersion() { var response = Get(new GetStatus()); return(AquariusServerVersion.Create(response.ReleaseName)); }
private AquariusServerVersion CreateDeveloperBuild() { return(AquariusServerVersion.Create("0")); }
public void Create_WithNegativeVersion_Throws() { Action action = () => AquariusServerVersion.Create("123.-123"); action.ShouldThrow <OverflowException>(); }
public void Create_WithEmptyVersion_Throws() { Action action = () => AquariusServerVersion.Create(string.Empty); action.ShouldThrow <FormatException>(); }
public void Create_WithNullVersion_Throws() { Action action = () => AquariusServerVersion.Create(null); action.ShouldThrow <ArgumentNullException>(); }
private static Context ParseArgs(string[] args) { var context = new Context(); var resolvedArgs = args .SelectMany(ResolveOptionsFromFile) .ToArray(); var options = new[] { new Option { Description = "Export configuration settings. Changes will trigger a full resync:" }, new Option { Key = nameof(context.Config.AquariusServer), Setter = value => context.Config.AquariusServer = value, Getter = () => context.Config.AquariusServer, Description = "AQTS server name" }, new Option { Key = nameof(context.Config.AquariusUsername), Setter = value => context.Config.AquariusUsername = value, Getter = () => context.Config.AquariusUsername, Description = "AQTS username" }, new Option { Key = nameof(context.Config.AquariusPassword), Setter = value => context.Config.AquariusPassword = value, Getter = () => context.Config.AquariusPassword, Description = "AQTS password" }, new Option { Key = nameof(context.Config.SosServer), Setter = value => context.Config.SosServer = value, Getter = () => context.Config.SosServer, Description = "SOS server name" }, new Option { Key = nameof(context.Config.SosUsername), Setter = value => context.Config.SosUsername = value, Getter = () => context.Config.SosUsername, Description = "SOS username" }, new Option { Key = nameof(context.Config.SosPassword), Setter = value => context.Config.SosPassword = value, Getter = () => context.Config.SosPassword, Description = "SOS password" }, new Option(), new Option { Description = "/Publish/v2/GetTimeSeriesUniqueIdList settings. Changes will trigger a full resync:" }, new Option { Key = nameof(context.Config.LocationIdentifier), Setter = value => context.Config.LocationIdentifier = value, Getter = () => context.Config.LocationIdentifier, Description = "Optional location filter." }, new Option { Key = nameof(context.Config.Publish), Setter = value => context.Config.Publish = string.IsNullOrEmpty(value) ? (bool?)null : bool.Parse(value), Getter = () => context.Config.Publish?.ToString(), Description = "Optional publish filter." }, new Option { Key = nameof(context.Config.ChangeEventType), Setter = value => context.Config.ChangeEventType = (ChangeEventType)Enum.Parse(typeof(ChangeEventType), value, true), Getter = () => context.Config.ChangeEventType?.ToString(), Description = $"Optional change event type filter. One of {string.Join(", ", Enum.GetNames(typeof(ChangeEventType)))}" }, new Option { Key = nameof(context.Config.Parameter), Setter = value => context.Config.Parameter = value, Getter = () => context.Config.Parameter, Description = "Optional parameter filter." }, new Option { Key = nameof(context.Config.ComputationIdentifier), Setter = value => context.Config.ComputationIdentifier = value, Getter = () => context.Config.ComputationIdentifier, Description = "Optional computation filter." }, new Option { Key = nameof(context.Config.ComputationPeriodIdentifier), Setter = value => context.Config.ComputationPeriodIdentifier = value, Getter = () => context.Config.ComputationPeriodIdentifier, Description = "Optional computation period filter." }, new Option { Key = nameof(context.Config.ExtendedFilters), Setter = value => { var split = value.Split('='); if (split.Length != 2) { throw new ExpectedException($"Can't parse '{value}' as Name=Value extended attribute filter"); } context.Config.ExtendedFilters.Add(new ExtendedAttributeFilter { FilterName = split[0], FilterValue = split[1] }); }, Getter = () => string.Empty, Description = "Extended attribute filter in Name=Value format. Can be set multiple times." }, new Option(), new Option { Description = "Aggressive time-series filtering. Changes will trigger a full resync:" }, new Option { Key = nameof(context.Config.TimeSeries), Setter = value => context.Config.TimeSeries.Add(ParseTimeSeriesFilter(value)), Getter = () => string.Empty, Description = "Time-series identifier regular expression filter. Can be specified multiple times." }, new Option { Key = "TimeSeriesDescription", Setter = value => context.Config.TimeSeriesDescriptions.Add(ParseTimeSeriesFilter(value)), Getter = () => string.Empty, Description = "Time-series description regular expression filter. Can be specified multiple times." }, new Option { Key = nameof(context.Config.Approvals), Setter = value => context.Config.Approvals.Add(ParseApprovalFilter(value)), Getter = () => string.Empty, Description = "Filter points by approval level or name. Can be specified multiple times." }, new Option { Key = nameof(context.Config.Grades), Setter = value => context.Config.Grades.Add(ParseGradeFilter(value)), Getter = () => string.Empty, Description = "Filter points by grade code or name. Can be specified multiple times." }, new Option { Key = nameof(context.Config.Qualifiers), Setter = value => context.Config.Qualifiers.Add(ParseQualifierFilter(value)), Getter = () => string.Empty, Description = "Filter points by qualifier. Can be specified multiple times." }, new Option(), new Option { Description = "Export duration configuration: Changes will trigger a full resync:" }, new Option { Key = nameof(context.Config.ExportDurationAttributeName), Setter = value => context.Config.ExportDurationAttributeName = value, Getter = () => context.Config.ExportDurationAttributeName, Description = "Name of time-series extended attribute storing the export duration." }, new Option { Key = nameof(context.Config.DefaultExportDurationDays), Setter = value => context.Config.DefaultExportDurationDays = int.Parse(value), Getter = () => $"{context.Config.DefaultExportDurationDays}", Description = "Default export duration when the extended attribute value cannot be parsed." }, new Option(), new Option { Description = "Other options: (Changing these values won't trigger a full resync)" }, new Option { Key = nameof(context.ConfigurationName), Setter = value => context.ConfigurationName = value, Getter = () => context.ConfigurationName, Description = "The name of the export configuration, to be saved in the AQTS global settings." }, new Option { Key = nameof(context.DryRun), Setter = value => context.DryRun = bool.Parse(value), Getter = () => context.DryRun.ToString(), Description = "When true, don't export to SOS. Only log the changes that would have been performed." }, new Option { Key = nameof(context.ForceResync), Setter = value => context.ForceResync = bool.Parse(value), Getter = () => context.ForceResync.ToString(), Description = "When true, force a full resync of all time-series." }, new Option { Key = nameof(context.NeverResync), Setter = value => context.NeverResync = bool.Parse(value), Getter = () => context.NeverResync.ToString(), Description = "When true, avoid full time-series resync, even when the algorithm recommends it." }, new Option { Key = nameof(context.ChangesSince), Setter = value => context.ChangesSince = DateTimeOffset.Parse(value), Getter = () => string.Empty, Description = "The starting changes-since time in ISO 8601 format. Defaults to the saved AQTS global setting value." }, new Option { Key = nameof(context.ApplyRounding), Setter = value => context.ApplyRounding = bool.Parse(value), Getter = () => context.ApplyRounding.ToString(), Description = "When true, export the rounded point values." }, new Option { Key = nameof(context.MaximumPointsPerObservation), Setter = value => context.MaximumPointsPerObservation = int.Parse(value), Getter = () => context.MaximumPointsPerObservation.ToString(), Description = "The maximum number of points per SOS observation" }, new Option { Key = nameof(context.MaximumPointsPerSensor), Setter = value => context.MaximumPointsPerSensor = int.Parse(value), Getter = () => context.MaximumPointsPerSensor.ToString(), Description = "The maximum number of points uploaded per SOS sensor" }, new Option { Key = nameof(context.MaximumPollDuration), Setter = value => context.MaximumPollDuration = TimeSpan.Parse(value, CultureInfo.InvariantCulture), Getter = () => context.MaximumPollDuration?.Humanize(2), Description = "The maximum duration before polling AQTS for more changes, in hh:mm:ss format. Defaults to the AQTS global setting." }, new Option { Key = nameof(context.Timeout), Setter = value => context.Timeout = TimeSpan.Parse(value, CultureInfo.InvariantCulture), Getter = () => context.Timeout.Humanize(2), Description = "The timeout used for all web requests, in hh:mm:ss format." }, new Option { Key = nameof(context.SosServerVersion), Setter = value => context.SosServerVersion = AquariusServerVersion.Create(value), Getter = () => context.SosServerVersion.ToString(), Description = "Expected 52North SOS server version" }, }; var usageMessage = $"Export time-series changes in AQTS time-series to an OGC SOS server." + $"\n" + $"\nusage: {ExeHelper.ExeName} [-option=value] [@optionsFile] ..." + $"\n" + $"\nSupported -option=value settings (/option=value works too):\n\n {string.Join("\n ", options.Select(o => o.UsageText()))}" + $"\n" + $"\nISO 8601 timestamps use a yyyy'-'mm'-'dd'T'HH':'mm':'ss'.'fffffffzzz format." + $"\n" + $"\n The 7 fractional seconds digits are optional." + $"\n The zzz timezone can be 'Z' for UTC, or +HH:MM, or -HH:MM" + $"\n" + $"\n Eg: 2017-04-01T00:00:00Z represents April 1st, 2017 in UTC." + $"\n" + $"\nUse the @optionsFile syntax to read more options from a file." + $"\n" + $"\n Each line in the file is treated as a command line option." + $"\n Blank lines and leading/trailing whitespace are ignored." + $"\n Comment lines begin with a # or // marker." ; foreach (var arg in resolvedArgs) { var match = ArgRegex.Match(arg); if (!match.Success) { if (HelpKeywords.Contains(arg)) { throw new ExpectedException($"Showing help page\n\n{usageMessage}"); } throw new ExpectedException($"Unknown command line argument: {arg}"); } var key = match.Groups["key"].Value.ToLower(); var value = match.Groups["value"].Value; var option = options.FirstOrDefault(o => o.Key != null && o.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)); if (option == null) { throw new ExpectedException($"Unknown -option=value: {arg}\n\n{usageMessage}"); } option.Setter(value); } if (string.IsNullOrWhiteSpace(context.Config.AquariusServer) || string.IsNullOrEmpty(context.Config.AquariusUsername) || string.IsNullOrEmpty(context.Config.AquariusPassword)) { throw new ExpectedException($"Ensure your AQTS server credentials are set."); } if (string.IsNullOrWhiteSpace(context.Config.SosServer) || string.IsNullOrEmpty(context.Config.SosUsername) || string.IsNullOrEmpty(context.Config.SosPassword)) { throw new ExpectedException($"Ensure your SOS server credentials are set."); } return(context); }