Exemplo n.º 1
0
        public void Delete()
        {
            var item = new ConfigEnvironment(new EnvironmentIdentifier("Foo", "Bar"));

            item.ApplyEvent(new ReplayedEvent
            {
                DomainEvent = new EnvironmentCreated(new EnvironmentIdentifier("Foo", "Bar")),
                UtcTime     = DateTime.UtcNow,
                Version     = 1
            });

            item.ApplyEvent(new ReplayedEvent
            {
                DomainEvent = new EnvironmentKeysImported(new EnvironmentIdentifier("Foo", "Bar"),
                                                          new[] { ConfigKeyAction.Set("Jar", "Jar", "Jar", "Jar") }),
                UtcTime = DateTime.UtcNow,
                Version = 1
            });

            item.Delete();

            Assert.True(item.Deleted, "item.Deleted");
            Assert.False(item.Created, "item.Created");
            Assert.Empty(item.Keys);
            Assert.Empty(item.KeyPaths);
        }
        public void CreateDeleteActionViaShortcut()
        {
            var action = ConfigKeyAction.Delete("Foo");

            Assert.Equal(ConfigKeyActionType.Delete, action.Type);
            Assert.Equal("Foo", action.Key);
        }
Exemplo n.º 3
0
        /// <summary>
        ///     overwrite all existing keys with the ones in <paramref name="keysToImport" />
        /// </summary>
        /// <param name="keysToImport"></param>
        /// <returns></returns>
        public IResult ImportKeys(ICollection <ConfigEnvironmentKey> keysToImport)
        {
            // copy dict as backup
            var oldKeys = Keys.ToDictionary(_ => _.Key, _ => _.Value);

            try
            {
                var newKeys = keysToImport.ToDictionary(k => k.Key, k => k, StringComparer.OrdinalIgnoreCase);

                Created = true;
                Keys    = newKeys;

                CapturedDomainEvents.Add(new EnvironmentKeysImported(
                                             Identifier,
                                             newKeys.Values
                                             .OrderBy(k => k.Key)
                                             .Select(k => ConfigKeyAction.Set(k.Key, k.Value, k.Description, k.Type))
                                             .ToArray()));

                _keyPaths = null;

                return(Result.Success());
            }
            catch (Exception)
            {
                // restore backup
                Keys = oldKeys;

                return(Result.Error("could not import all keys into this environment", ErrorCode.Undefined));
            }
        }
        public void ValidateConfigKeyActions(ConfigKeyAction action)
        {
            var validator = CreateValidator();

            var result = validator.ValidateDomainEvent(new EnvironmentKeysModified(new EnvironmentIdentifier("Foo", "Bar"), new[] { action }));

            Assert.True(result.IsError);
        }
        public async Task GetKeysWithoutRoot()
        {
            var domainObjectStore = new Mock <IDomainObjectStore>(MockBehavior.Strict);

            domainObjectStore.Setup(dos => dos.ReplayObject(It.IsAny <ConfigEnvironment>(), It.IsAny <string>()))
            .ReturnsAsync((ConfigEnvironment str, string id) =>
            {
                str.ApplyEvent(new ReplayedEvent
                {
                    DomainEvent = new EnvironmentCreated(new EnvironmentIdentifier("Foo", "Bar")),
                    UtcTime     = DateTime.UtcNow,
                    Version     = 4710
                });
                str.ApplyEvent(new ReplayedEvent
                {
                    DomainEvent = new EnvironmentKeysImported(new EnvironmentIdentifier("Foo", "Bar"), new[]
                    {
                        ConfigKeyAction.Set("Foo", "FooValue"),
                        ConfigKeyAction.Set("Foo/Bar", "BarValue"),
                        ConfigKeyAction.Set("Foo/Bar/Baz", "BazValue")
                    }),
                    UtcTime = DateTime.UtcNow,
                    Version = 4711
                });
                return(Result.Success(str));
            })
            .Verifiable();

            var eventStore = new Mock <IEventStore>(MockBehavior.Strict);

            eventStore.Setup(es => es.ReplayEventsAsStream(
                                 It.IsAny <Func <(StoredEvent StoredEvent, DomainEventMetadata Metadata), bool> >(),
                                 It.IsAny <Func <(StoredEvent StoredEvent, DomainEvent DomainEvent), bool> >(),
                                 It.IsAny <int>(),
                                 It.IsAny <StreamDirection>(),
                                 It.IsAny <long>()))
            .Returns(Task.CompletedTask);

            var store = new EnvironmentProjectionStore(eventStore.Object,
                                                       domainObjectStore.Object,
                                                       _logger,
                                                       new ICommandValidator[0]);

            var result = await store.GetKeys(new EnvironmentKeyQueryParameters
            {
                Environment = new EnvironmentIdentifier("Foo", "Bar"),
                Filter      = "Foo/",
                RemoveRoot  = "Foo",
                Range       = QueryRange.All
            });

            Assert.Empty(result.Message);
            Assert.False(result.IsError, "result.IsError");
            Assert.NotEmpty(result.Data);

            domainObjectStore.Verify();
            eventStore.Verify();
        }
        /// <summary>
        ///     Add or Update existing Variables, and record all events necessary for this action
        /// </summary>
        /// <param name="updatedKeys"></param>
        /// <returns></returns>
        public IResult ModifyVariables(IDictionary <string, string> updatedKeys)
        {
            if (updatedKeys is null || !updatedKeys.Any())
            {
                return(Result.Error("null or empty variables given", ErrorCode.InvalidData));
            }

            // record all new keys to remove in case of exception
            var recordedAdditions = new List <string>();

            // maps key to old value - to revert back in case of exception
            var recordedUpdates = new Dictionary <string, string>();

            try
            {
                foreach (var(key, value) in updatedKeys)
                {
                    if (Variables.ContainsKey(key))
                    {
                        recordedUpdates[key] = Variables[key];
                        Variables[key]       = value;
                    }
                    else
                    {
                        recordedAdditions.Add(key);
                        Variables[key] = value;
                    }
                }

                // all items that have actually been added to or changed in this structure are saved as event
                // skipping those that may not be there anymore and reducing the Event-Size or skipping the event entirely
                var recordedChanges = recordedAdditions.Concat(updatedKeys.Keys).ToList();

                if (recordedChanges.Any())
                {
                    CapturedDomainEvents.Add(
                        new StructureVariablesModified(
                            Identifier,
                            recordedChanges.Select(k => ConfigKeyAction.Set(k, Variables[k]))
                            .ToArray()));
                }

                return(Result.Success());
            }
            catch (Exception)
            {
                foreach (var addedKey in recordedAdditions)
                {
                    Variables.Remove(addedKey);
                }
                foreach (var(key, value) in recordedUpdates)
                {
                    Variables[key] = value;
                }

                return(Result.Error("could not update all variables for this Structure", ErrorCode.Undefined));
            }
        }
        /// <summary>
        ///     compare the source-env with all target-envs and return the necessary actions to reach each target
        /// </summary>
        /// <param name="targetEnvironment"></param>
        /// <param name="sourceEnvironments"></param>
        /// <returns></returns>
        private IList <EnvironmentComparison> CompareEnvironments(EnvironmentExport targetEnvironment,
                                                                  IDictionary <EnvironmentIdentifier, DtoConfigKey[]> sourceEnvironments)
        {
            var comparisons = new List <EnvironmentComparison>();

            try
            {
                foreach (var(id, sourceKeys) in sourceEnvironments)
                {
                    Output.WriteVerboseLine($"comparing '{targetEnvironment.Category}/{targetEnvironment.Name}' <=> '{id}'");

                    var changedKeys = (Mode & ComparisonMode.Add) != 0
                                          ? targetEnvironment.Keys.Where(key =>
                    {
                        // if the given key does not exist in the target environment or is somehow changed
                        // we add it to the list of changed keys for review
                        var sourceKey = sourceKeys.FirstOrDefault(k => k.Key.Equals(key.Key));

                        // null and "" are treated as equals here
                        return(sourceKey is null ||
                               !(sourceKey.Value ?? string.Empty).Equals(key.Value ?? string.Empty) ||
                               !(sourceKey.Type ?? string.Empty).Equals(key.Type ?? string.Empty) ||
                               !(sourceKey.Description ?? string.Empty).Equals(key.Description ?? string.Empty));
                    }).ToList()
                                          : new List <EnvironmentKeyExport>();

                    var deletedKeys = (Mode & ComparisonMode.Delete) != 0
                                          ? sourceKeys.Where(sk =>
                    {
                        // if any target-key doesn't exist in the source any more,
                        // we add it to the list of deleted keys for review
                        return(targetEnvironment.Keys.All(tk => !tk.Key.Equals(sk.Key)));
                    }).ToList()
                                          : new List <DtoConfigKey>();

                    comparisons.Add(new EnvironmentComparison
                    {
                        Source          = new EnvironmentIdentifier(targetEnvironment.Category, targetEnvironment.Name),
                        Target          = id,
                        RequiredActions = changedKeys.Select(c => KeepNullProperties
                                                                      ? ConfigKeyAction.Set(c.Key, c.Value, c.Description, c.Type)
                                                                      : ConfigKeyAction.Set(c.Key,
                                                                                            c.Value ?? string.Empty,
                                                                                            c.Description ?? string.Empty,
                                                                                            c.Type ?? string.Empty))
                                          .Concat(deletedKeys.Select(d => ConfigKeyAction.Delete(d.Key)))
                                          .ToList()
                    });
                }
            }
            catch (Exception e)
            {
                Output.WriteLine($"error while comparing environments: {e}");
                return(new List <EnvironmentComparison>());
            }

            return(comparisons);
        }
        public void CreateSetActionViaShortcut()
        {
            var action = ConfigKeyAction.Set("Foo", "Bar");

            Assert.NotNull(action);
            Assert.Equal(ConfigKeyActionType.Set, action.Type);
            Assert.Equal("Foo", action.Key);
            Assert.Equal("Bar", action.Value);
        }
        public void CreateDeleteActionViaConstructor()
        {
            var action = new ConfigKeyAction(ConfigKeyActionType.Delete, "Foo", "Bar", "Baz", "Que?");

            Assert.Equal(ConfigKeyActionType.Delete, action.Type);
            Assert.Equal("Foo", action.Key);
            Assert.Equal("Bar", action.Value);
            Assert.Equal("Baz", action.Description);
            Assert.Equal("Que?", action.ValueType);
        }
        public async Task DeleteKeys()
        {
            var domainObjectStore = new Mock <IDomainObjectStore>(MockBehavior.Strict);

            domainObjectStore.Setup(dos => dos.ReplayObject(It.IsAny <ConfigEnvironment>(), It.IsAny <string>()))
            .ReturnsAsync((ConfigEnvironment str, string id) =>
            {
                str.ApplyEvent(new ReplayedEvent
                {
                    DomainEvent = new EnvironmentCreated(new EnvironmentIdentifier("Foo", "Bar")),
                    UtcTime     = DateTime.UtcNow,
                    Version     = 4710
                });
                str.ApplyEvent(new ReplayedEvent
                {
                    DomainEvent = new EnvironmentKeysImported(new EnvironmentIdentifier("Foo", "Bar"), new[]
                    {
                        ConfigKeyAction.Set("Foo", "FooValue"),
                        ConfigKeyAction.Set("Bar", "BarValue"),
                        ConfigKeyAction.Set("Baz", "BazValue")
                    }),
                    UtcTime = DateTime.UtcNow,
                    Version = 4711
                });
                return(Result.Success(str));
            })
            .Verifiable();

            var eventStore = new Mock <IEventStore>(MockBehavior.Strict);

            eventStore.Setup(es => es.ReplayEventsAsStream(
                                 It.IsAny <Func <(StoredEvent StoredEvent, DomainEventMetadata Metadata), bool> >(),
                                 It.IsAny <Func <(StoredEvent StoredEvent, DomainEvent DomainEvent), bool> >(),
                                 It.IsAny <int>(),
                                 It.IsAny <StreamDirection>(),
                                 It.IsAny <long>()))
            .Returns(Task.CompletedTask);

            eventStore.Setup(es => es.WriteEvents(It.IsAny <IList <DomainEvent> >()))
            .ReturnsAsync(4712)
            .Verifiable("events not written to stream");

            var store = new EnvironmentProjectionStore(eventStore.Object,
                                                       domainObjectStore.Object,
                                                       _logger,
                                                       new ICommandValidator[0]);

            var result = await store.DeleteKeys(new EnvironmentIdentifier("Foo", "Bar"), new[] { "Bar", "Baz" });

            Assert.Empty(result.Message);
            Assert.False(result.IsError, "result.IsError");

            domainObjectStore.Verify();
            eventStore.Verify();
        }
        public void ValidateEnvironmentKeysImported()
        {
            var validator = CreateValidator();

            var result = validator.ValidateDomainEvent(new EnvironmentKeysImported(new EnvironmentIdentifier("Foo", "Bar"), new[]
            {
                ConfigKeyAction.Set("Foo", "Bar", "description", "type")
            }));

            Assert.False(result.IsError);
        }
        public void ValidateStructureVariablesModified()
        {
            var validator = CreateValidator();

            var result = validator.ValidateDomainEvent(new StructureVariablesModified(new StructureIdentifier("Foo", 42), new[]
            {
                ConfigKeyAction.Set("Foo", "Bar"),
                ConfigKeyAction.Delete("Baz")
            }));

            Assert.False(result.IsError);
        }
        public void ValidateStructureCreatedVariables()
        {
            var validator = CreateValidator();

            var result = validator.ValidateDomainEvent(
                new StructureVariablesModified(
                    new StructureIdentifier("Foo", 42),
                    new[]
            {
                ConfigKeyAction.Set(string.Empty, string.Empty),
                ConfigKeyAction.Set(null, null)
            }));

            Assert.True(result.IsError);
        }
Exemplo n.º 14
0
        public async Task CompilationFailsWhenStructureNotFound()
        {
            var config = new PreparedConfiguration(
                new ConfigurationIdentifier(
                    new EnvironmentIdentifier("Foo", "Bar"),
                    new StructureIdentifier("Foo", 42),
                    4711));

            var store = new Mock <IDomainObjectStore>(MockBehavior.Strict);

            store.Setup(s => s.ReplayObject(It.IsAny <ConfigEnvironment>(),
                                            It.IsAny <string>(),
                                            It.IsAny <long>()))
            .ReturnsAsync((ConfigEnvironment env, string id, long version) =>
            {
                env.ApplyEvent(new ReplayedEvent
                {
                    UtcTime     = DateTime.UtcNow,
                    Version     = 1,
                    DomainEvent = new EnvironmentKeysImported(env.Identifier, new[]
                    {
                        ConfigKeyAction.Set("Foo", "Bar", "", ""),
                        ConfigKeyAction.Set("Jar", "Jar", "", "")
                    })
                });
                return(Result.Success(env));
            })
            .Verifiable("Environment not retrieved");

            store.Setup(s => s.ReplayObject(It.IsAny <ConfigStructure>(),
                                            It.IsAny <string>(),
                                            It.IsAny <long>()))
            .ReturnsAsync(() => Result.Error <ConfigStructure>(string.Empty, ErrorCode.DbQueryError))
            .Verifiable("Structure not retrieved");

            var compiler   = new Mock <IConfigurationCompiler>(MockBehavior.Strict);
            var parser     = new Mock <IConfigurationParser>(MockBehavior.Strict);
            var translator = new Mock <IJsonTranslator>(MockBehavior.Strict);

            var result = await config.Compile(store.Object, compiler.Object, parser.Object, translator.Object);

            Assert.True(result.IsError);

            store.Verify();
        }
Exemplo n.º 15
0
        public void ReplayHandlesModifiedVariables()
        {
            var item = new ConfigStructure(new StructureIdentifier("FooBar", 42));

            item.Create(new Dictionary <string, string> {
                { "Foo", "Bar" }
            },
                        new Dictionary <string, string> {
                { "Bar", "Baz" }
            });

            item.ApplyEvent(new ReplayedEvent
            {
                Version     = 1,
                DomainEvent = new StructureVariablesModified(new StructureIdentifier("FooBar", 42),
                                                             new[] { ConfigKeyAction.Set("Foo", "BarBarBar") }),
                UtcTime = DateTime.UtcNow
            });

            Assert.Equal(1, item.CurrentVersion);
            Assert.Equal("BarBarBar", item.Variables["Foo"]);
        }
Exemplo n.º 16
0
        /// <summary>
        ///     validate a single <see cref="ConfigKeyAction" />
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        private IResult ValidateConfigKeyAction(ConfigKeyAction action)
        {
            if (action is null)
            {
                return(Result.Error("invalid data: action is null", ErrorCode.ValidationFailed));
            }

            if (string.IsNullOrWhiteSpace(action.Key))
            {
                return(Result.Error("invalid data: no key defined", ErrorCode.ValidationFailed));
            }

            switch (action.Type)
            {
            case ConfigKeyActionType.Set:
            case ConfigKeyActionType.Delete:
                break;

            default:
                return(Result.Error($"invalid data: invalid Type {action.Type:D} / '{action.Type:G}'; key='{action.Key}'", ErrorCode.ValidationFailed));
            }

            return(Result.Success());
        }
Exemplo n.º 17
0
        /// <summary>
        ///     add new, or change some of the held keys, and create the appropriate events for that
        /// </summary>
        /// <param name="keysToAdd"></param>
        /// <returns></returns>
        public IResult UpdateKeys(ICollection <ConfigEnvironmentKey> keysToAdd)
        {
            if (keysToAdd is null || !keysToAdd.Any())
            {
                return(Result.Error("null or empty list given", ErrorCode.InvalidData));
            }

            var addedKeys   = new List <ConfigEnvironmentKey>();
            var updatedKeys = new Dictionary <string, ConfigEnvironmentKey>();

            try
            {
                foreach (var newEntry in keysToAdd)
                {
                    if (Keys.ContainsKey(newEntry.Key))
                    {
                        var oldEntry = Keys[newEntry.Key];
                        if (oldEntry.Description == newEntry.Description &&
                            oldEntry.Type == newEntry.Type &&
                            oldEntry.Value == newEntry.Value)
                        {
                            // if the key and all metadata is same before and after the change,
                            // we might as well skip this change altogether
                            continue;
                        }

                        updatedKeys.Add(newEntry.Key, Keys[newEntry.Key]);
                        Keys[newEntry.Key] = newEntry;
                    }
                    else
                    {
                        addedKeys.Add(newEntry);
                        Keys.Add(newEntry.Key, newEntry);
                    }
                }

                // all items that have actually been added to or changed in this environment are saved as event
                // skipping those that may not be there anymore and reducing the Event-Size or skipping the event entirely
                // ---
                // updatedKeys maps key => oldValue, so the old value can be restored if something goes wrong
                // this means we have to get the current/new/overwritten state based on the updatedKeys.Keys
                var recordedChanges = addedKeys.Concat(updatedKeys.Keys.Select(k => Keys[k]))
                                      .ToList();

                if (recordedChanges.Any())
                {
                    CapturedDomainEvents.Add(
                        new EnvironmentKeysModified(
                            Identifier,
                            recordedChanges.Select(k => ConfigKeyAction.Set(k.Key, k.Value, k.Description, k.Type))
                            .ToArray()));
                }

                _keyPaths = null;

                return(Result.Success());
            }
            catch (Exception)
            {
                foreach (var addedKey in addedKeys)
                {
                    Keys.Remove(addedKey.Key);
                }
                foreach (var(key, value) in updatedKeys)
                {
                    Keys[key] = value;
                }

                return(Result.Error("could not update all keys in the environment", ErrorCode.Undefined));
            }
        }
Exemplo n.º 18
0
        public async Task NoThrowOnCompilationException()
        {
            var config = new PreparedConfiguration(
                new ConfigurationIdentifier(
                    new EnvironmentIdentifier("Foo", "Bar"),
                    new StructureIdentifier("Foo", 42),
                    4711));

            var store = new Mock <IDomainObjectStore>(MockBehavior.Strict);

            store.Setup(s => s.ReplayObject(It.IsAny <ConfigEnvironment>(),
                                            It.IsAny <string>(),
                                            It.IsAny <long>()))
            .ReturnsAsync((ConfigEnvironment env, string id, long version) =>
            {
                env.ApplyEvent(new ReplayedEvent
                {
                    UtcTime     = DateTime.UtcNow,
                    Version     = 1,
                    DomainEvent = new EnvironmentKeysImported(env.Identifier, new[]
                    {
                        ConfigKeyAction.Set("Foo", "Bar", "", ""),
                        ConfigKeyAction.Set("Jar", "Jar", "", "")
                    })
                });
                return(Result.Success(env));
            })
            .Verifiable("Environment not retrieved");

            store.Setup(s => s.ReplayObject(It.IsAny <ConfigStructure>(),
                                            It.IsAny <string>(),
                                            It.IsAny <long>()))
            .ReturnsAsync((ConfigStructure str, string id, long version) =>
            {
                str.ApplyEvent(new ReplayedEvent
                {
                    UtcTime     = DateTime.UtcNow,
                    Version     = 1,
                    DomainEvent = new StructureCreated(str.Identifier,
                                                       new Dictionary <string, string> {
                        { "Ref", "{{Foo}}{{Jar}}" }
                    },
                                                       new Dictionary <string, string>())
                });
                return(Result.Success(str));
            })
            .Verifiable("Structure not retrieved");

            var compiler = new Mock <IConfigurationCompiler>(MockBehavior.Strict);

            compiler.Setup(c => c.Compile(It.IsAny <EnvironmentCompilationInfo>(), It.IsAny <StructureCompilationInfo>(), It.IsAny <IConfigurationParser>()))
            .Throws <Exception>()
            .Verifiable();

            var parser     = new Mock <IConfigurationParser>(MockBehavior.Strict);
            var translator = new Mock <IJsonTranslator>(MockBehavior.Strict);

            var result = await config.Compile(store.Object, compiler.Object, parser.Object, translator.Object);

            Assert.True(result.IsError);

            store.Verify();
            compiler.Verify();
        }