Esempio n. 1
0
        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);
        }
Esempio n. 4
0
        public void IsDeveloperBuild_DetectsCorrectly(string reason, string versionText, bool expected)
        {
            var version = AquariusServerVersion.Create(versionText);
            var actual  = version.IsDeveloperBuild();

            actual.ShouldBeEquivalentTo(expected, reason);
        }
Esempio n. 5
0
        public void Dispose_With3xConnection_DoesNotCallDeleteSession()
        {
            _client.ServerVersion = AquariusServerVersion.Create("3.10");

            _client.Dispose();

            AssertExpectedDeleteSessionRequests(0);
        }
Esempio n. 6
0
        private SamplesClient(IServiceClient client, string apiToken)
        {
            SetupServiceStack();

            _client = client;

            Client.AddHeader(AuthorizationHeaderKey, $"token {apiToken}");

            ServerVersion = GetServerVersion();

            Log.Info($"Connected to {GetBaseUri()} ({ServerVersion}) ...");
        }
Esempio n. 7
0
        private SosClient(string hostUrl, string username, string password, AquariusServerVersion sosServerVersion)
        {
            SosServerVersion = sosServerVersion;
            HostUrl          = hostUrl.TrimEnd('/');
            Username         = username;
            Password         = password;

            AdaptToSosVersion();


            ConfigureJsonOnce();
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
            }
        }
Esempio n. 10
0
        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");
            }
        }
Esempio n. 11
0
        private AquariusServerVersion GetServerVersion()
        {
            var response = Get(new GetStatus());

            return(AquariusServerVersion.Create(response.ReleaseName));
        }
 private AquariusServerVersion CreateDeveloperBuild()
 {
     return(AquariusServerVersion.Create("0"));
 }
Esempio n. 13
0
        public void Create_WithNegativeVersion_Throws()
        {
            Action action = () => AquariusServerVersion.Create("123.-123");

            action.ShouldThrow <OverflowException>();
        }
Esempio n. 14
0
        public void Create_WithEmptyVersion_Throws()
        {
            Action action = () => AquariusServerVersion.Create(string.Empty);

            action.ShouldThrow <FormatException>();
        }
Esempio n. 15
0
        public void Create_WithNullVersion_Throws()
        {
            Action action = () => AquariusServerVersion.Create(null);

            action.ShouldThrow <ArgumentNullException>();
        }
Esempio n. 16
0
        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);
        }