Esempio n. 1
0
        public async Task <object> Execute <TService>(object args = null) where TService : IViewService
        {
            Type type = typeof(TService);

            IViewService service;

            if (!ServiceMap.TryGetValue(type, out service))
            {
                throw new InvalidOperationException($"Unknown service of type {type}");
            }

            return(await service.Execute(Window, args));
        }
Esempio n. 2
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="serviceMap">The service map describing this service and potentially other services.</param>
        /// <param name="name">The name of this service within <see cref="ServiceMap"/>.</param>
        /// <param name="branch">Optionally specifies the build branch.</param>
        /// <param name="commit">Optionally specifies the branch commit.</param>
        /// <param name="isDirty">Optionally specifies whether there are uncommit changes to the branch.</param>
        /// <exception cref="KeyNotFoundException">
        /// Thrown if there is no service description for <paramref name="name"/>
        /// within <see cref="serviceMap"/>.
        /// </exception>
        /// <remarks>
        /// <para>
        /// For those of you using Git for source control, you'll want to pass the
        /// information about the branch and latest commit you're you service was
        /// built from here.  We use the <a href="https://www.nuget.org/packages/GitInfo/">GitInfo</a>
        /// nuget package to obtain this information from the local Git repository.
        /// </para>
        /// <para>
        /// Alternatively, you could try to map properties from your source
        /// control environment to these parameters, pass your version string as
        /// <paramref name="branch"/>, or simply ignore these parameters.
        /// </para>
        /// </remarks>
        public KubeService(
            ServiceMap serviceMap,
            string name,
            string branch      = null,
            string commit      = null,
            bool isDirty       = false,
            bool noProcessExit = false)
        {
            Covenant.Requires <ArgumentNullException>(serviceMap != null);
            Covenant.Requires <ArgumentNullException>(!string.IsNullOrEmpty(name));

            if (!serviceMap.TryGetValue(name, out var description))
            {
                throw new KeyNotFoundException($"The service map does not include a service definition for [{name}].");
            }

            this.ServiceMap           = serviceMap;
            this.Description          = description;
            this.InProduction         = !NeonHelper.IsDevWorkstation;
            this.Terminator           = new ProcessTerminator();
            this.environmentVariables = new Dictionary <string, string>();
            this.configFiles          = new Dictionary <string, FileInfo>();

            // Git version info:

            this.GitVersion = null;

            if (!string.IsNullOrEmpty(branch))
            {
                this.GitVersion = branch;

                if (!string.IsNullOrEmpty(commit))
                {
                    this.GitVersion += $"-{commit}";
                }

                if (isDirty)
                {
                    this.GitVersion += $"-dirty";
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Used to start the fixture within a <see cref="ComposedFixture"/>.
        /// </summary>
        /// <param name="serviceCreator">Callback that creates and returns the new service instance.</param>
        /// <param name="serviceMap">
        /// Optionally passed as the service map describing an emulated deployment.  When this is
        /// not <c>null</c>, the fixture will call <see cref="NeonService.Name"/> on the service
        /// returned by your service creator function and then look up the service by name from
        /// the <paramref name="serviceMap"/>.  If an entry exists for the service, the fixture will
        /// add any environment variables or configuration files from the <see cref="ServiceDescription"/>
        /// to the <see cref="NeonService"/> before starting it.
        /// </param>
        /// <param name="readyTimeout">
        /// Optionally specifies the maximum time the fixture should wait for the service to transition
        /// to the <see cref="NeonServiceStatus.Running"/> state.  This defaults to <b>30 seconds</b>.
        /// </param>
        /// <exception cref="TimeoutException">
        /// Thrown if the service didn't transition to the running (or terminated) state
        /// within <paramref name="readyTimeout"/>.
        /// </exception>
        public void StartAsComposed(Func <TService> serviceCreator, ServiceMap serviceMap = null, TimeSpan readyTimeout = default)
        {
            Covenant.Requires <ArgumentNullException>(serviceCreator != null, nameof(serviceCreator));

            if (readyTimeout == default)
            {
                readyTimeout = defaultRunningTimeout;
            }

            base.CheckWithinAction();

            if (IsRunning)
            {
                return;
            }

            Service = serviceCreator();
            Covenant.Assert(Service != null);

            // Indicate that the service is not running in production.

            Service.InProduction = false;

            // Configure the service is a service map was passed and there's a service description
            // for the service.

            if (serviceMap != null && serviceMap.TryGetValue(Service.Name, out var serviceDescription))
            {
                foreach (var item in serviceDescription.TestEnvironmentVariables)
                {
                    Service.SetEnvironmentVariable(item.Key, item.Value);
                }

                foreach (var item in serviceDescription.TestTextConfigFiles)
                {
                    var path = item.Key;
                    var text = item.Value;

                    if (string.IsNullOrEmpty(path))
                    {
                        continue;
                    }

                    Service.SetConfigFile(path, text ?? string.Empty);
                }

                foreach (var item in serviceDescription.TestBinaryConfigFiles)
                {
                    var path  = item.Key;
                    var bytes = item.Value;

                    if (string.IsNullOrEmpty(path))
                    {
                        continue;
                    }

                    Service.SetConfigFile(path, bytes ?? Array.Empty <byte>());
                }
            }

            // Start the service.

            serviceTask = Service.RunAsync();

            // Wait for the service to signal that it's running or has terminated.

            try
            {
                NeonHelper.WaitFor(() => Service.Status == NeonServiceStatus.Running || Service.Status == NeonServiceStatus.Terminated, readyTimeout);

                if (Service.ExitException != null)
                {
                    throw new Exception($"Unexpected [{Service.ExitException.GetType().Name}] thrown by the service's [OnRunAsync()] method.", Service.ExitException);
                }
            }
            catch (TimeoutException)
            {
                // Throw a nicer exception that explains what's happened in more detail.

                throw new TimeoutException($"Service [{Service.Name}]'s [{typeof(TService).Name}.OnRunAsync()] method did not call [{nameof(NeonService.StartedAsync)}()] within [{readyTimeout}] indicating that the service is ready.  Ensure that [{nameof(NeonService.StartedAsync)}()] is being called or increase the timeout.");
            }

            IsRunning = Service.Status == NeonServiceStatus.Running;
        }