package org.rapidoid.http; /* * #%L * rapidoid-integration-tests * %% * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import org.junit.Test; import org.rapidoid.annotation.Authors; import org.rapidoid.annotation.Since; import org.rapidoid.collection.Coll; import org.rapidoid.config.Conf; import org.rapidoid.config.ConfigChanges; import org.rapidoid.data.JSON; import org.rapidoid.io.IO; import org.rapidoid.log.Log; import org.rapidoid.setup.App; import org.rapidoid.u.U; import org.rapidoid.util.Msc; import java.util.List; import java.util.Map; @Authors("Nikolche Mihajlovski") @Since("5.3.0") public class HTTPRefreshingConfigTest extends IsolatedIntegrationTest { @Test public void testRefreshingConfig() { String cfgDir = createTempDir("cfgDir-test"); Conf.reset(); Conf.setPath(cfgDir); App.boot(); List<ConfigChanges> rootChanges = Coll.synchronizedList(); List<ConfigChanges> apiChanges = Coll.synchronizedList(); Conf.ROOT.addChangeListener(changes -> { if (changes.initial) { eq(changes.added, withoutEmptySections(Conf.ROOT.toMap())); } else { U.print("******** ", changes); rootChanges.add(changes); } }); Conf.API.addChangeListener(changes -> { if (changes.initial) { eq(changes.added, withoutEmptySections(Conf.API.toMap())); } else { U.print("*** API ", changes); apiChanges.add(changes); } if (changes.initial) fail("There's not initial API config!"); }); Conf.HTTP.addChangeListener(changes -> { U.print("*** HTTP ", changes); if (changes.initial) { eq(changes.added, Conf.HTTP.toMap()); } else { fail("There are not additional HTTP config changes!"); } }); Conf.ROOT.sub("abcd").addChangeListener(changes -> { fail("The 'abcd' config change is not expected!"); }); String cfgFile = Msc.path(cfgDir, "config.yml"); eq(Conf.API.toMap(), U.map()); eq(Conf.ROOT.getChangesSince(null).added, withoutEmptySections(Conf.ROOT.toMap())); eq(Conf.API.getChangesSince(null).added, withoutEmptySections(Conf.API.toMap())); eq(Conf.HTTP.getChangesSince(null).added, withoutEmptySections(Conf.HTTP.toMap())); U.sleep(2000); // give the Watch service some time to start for (int step = 1; step <= 5; step++) { exerciseConfigChanges(step, cfgFile); } verify("root-changes", JSON.prettify(rootChanges)); verify("api-changes", JSON.prettify(apiChanges)); } private Map<String, Object> withoutEmptySections(Map<String, Object> map) { Map<String, Object> withoutEmptySections = U.map(); for (Map.Entry<String, Object> e : map.entrySet()) { Object value = e.getValue(); boolean isEmptyMap = value instanceof Map && ((Map) value).isEmpty(); if (!isEmptyMap) { withoutEmptySections.put(e.getKey(), value); } } return withoutEmptySections; } private void exerciseConfigChanges(int step, String cfg) { changeConfig(cfg, "cfg-" + step + ".yml"); verify("cfg-api-" + step, JSON.prettify(Conf.API.toMap())); // verifyRoutes("routes-" + step); } private void changeConfig(String cfg, String loadFrom) { Log.info("Updating configuration", "file", cfg); IO.save(cfg, IO.load(loadFrom)); U.sleep(2000); // wait 2 seconds, lastModified might have 1 second resolution } }