[TEST] improved registered actions sanity check test

Shield needs to know about all the actions that are registered in core. We now check not only the external actions, meaning the classes that implement the Action interface, exposed via java api, but also all the transport handlers registered through the transport, which will contains all shard/node level actions plus the internal actions that are not exposed via java api.

We maintain two files, one for external actions, and one for the internal ones, and we check whether actions have been added or removed to/from core, to make sure we know about those changes.

Original commit: elastic/x-pack-elasticsearch@d6b68c44ee
This commit is contained in:
javanna 2014-10-10 11:53:18 +02:00 committed by Luca Cavanna
parent 5514201d4d
commit bad27996f9
4 changed files with 203 additions and 87 deletions

View File

@ -1,84 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.authz;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.Action;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.util.Callback;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static org.hamcrest.Matchers.hasItem;
/**
*
*/
public class KnownActionsSanityCheckTests extends ElasticsearchTestCase {
private ImmutableSet<String> knownActions;
@Before
public void init() throws Exception {
final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
try (InputStream input = KnownActionsSanityCheckTests.class.getResourceAsStream("actions")) {
Streams.readAllLines(input, new Callback<String>() {
@Override
public void handle(String action) {
builder.add(action);
}
});
} catch (IOException ioe) {
throw new ElasticsearchIllegalStateException("Could not load known actions", ioe);
}
knownActions = builder.build();
}
@Test
public void testAllShieldActionsAreKnown() throws Exception {
ClassPath classPath = ClassPath.from(Action.class.getClassLoader());
ImmutableSet<ClassPath.ClassInfo> infos = classPath.getTopLevelClassesRecursive(Action.class.getPackage().getName());
for (ClassPath.ClassInfo info : infos) {
Class clazz = info.load();
if (Action.class.isAssignableFrom(clazz)) {
String name = extractActionName(clazz);
if (name != null) {
assertThat("elasticsearch core action [" + name + "] is unknown to shield", knownActions, hasItem(name));
}
}
}
}
private String extractActionName(Class clazz) throws Exception {
if (Modifier.isAbstract(clazz.getModifiers())) {
return null;
}
Field field = getField(clazz, "INSTANCE");
if (field == null || !Modifier.isStatic(field.getModifiers())) {
return null;
}
Action action = (Action) field.get(null);
return action.name();
}
private static Field getField(Class clazz, String name) {
try {
return clazz.getField(name);
} catch (NoSuchFieldException nsfe) {
return null;
}
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.transport;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import org.elasticsearch.ElasticsearchIllegalStateException;
import org.elasticsearch.action.Action;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.util.Callback;
import org.elasticsearch.shield.test.ShieldIntegrationTest;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
public class KnownActionsTests extends ShieldIntegrationTest {
private static ImmutableSet<String> knownActions;
private static ImmutableSet<String> knownHandlers;
private static ImmutableSet<String> coreActions;
@BeforeClass
public static void init() throws Exception {
knownActions = loadKnownActions();
knownHandlers = loadKnownHandlers();
coreActions = loadCoreActions();
}
@Test
public void testAllCoreTransportHandlersAreKnown() {
TransportService transportService = internalCluster().getInstance(TransportService.class);
for (String handler : transportService.serverHandlers.keySet()) {
if (!knownActions.contains(handler)) {
assertThat("elasticsearch core transport handler [" + handler + "] is unknown to shield", knownHandlers, hasItem(handler));
}
}
}
@Test
public void testAllCoreActionsAreKnown() throws Exception {
for (String action : coreActions) {
assertThat("elasticsearch core action [" + action + "] is unknown to shield", knownActions, hasItem(action));
}
}
@Test
public void testAllKnownActionsAreValid() {
for (String knownAction : knownActions) {
assertThat("shield known action [" + knownAction + "] is unknown to core", coreActions, hasItems(knownAction));
}
}
@Test
public void testAllKnownTransportHandlersAreValid() {
TransportService transportService = internalCluster().getInstance(TransportService.class);
for (String knownHandler : knownHandlers) {
assertThat("shield known action [" + knownHandler + "] is unknown to core", transportService.serverHandlers.keySet(), hasItems(knownHandler));
}
}
private static ImmutableSet<String> loadKnownActions() {
final ImmutableSet.Builder<String> knownActionsBuilder = ImmutableSet.builder();
try (InputStream input = KnownActionsTests.class.getResourceAsStream("actions")) {
Streams.readAllLines(input, new Callback<String>() {
@Override
public void handle(String action) {
knownActionsBuilder.add(action);
}
});
} catch (IOException ioe) {
throw new ElasticsearchIllegalStateException("Could not load known actions", ioe);
}
return knownActionsBuilder.build();
}
private static ImmutableSet<String> loadKnownHandlers() {
final ImmutableSet.Builder<String> knownHandlersBuilder = ImmutableSet.builder();
try (InputStream input = KnownActionsTests.class.getResourceAsStream("handlers")) {
Streams.readAllLines(input, new Callback<String>() {
@Override
public void handle(String action) {
knownHandlersBuilder.add(action);
}
});
} catch (IOException ioe) {
throw new ElasticsearchIllegalStateException("Could not load known handlers", ioe);
}
return knownHandlersBuilder.build();
}
private static ImmutableSet<String> loadCoreActions() throws IOException, IllegalAccessException {
ImmutableSet.Builder<String> coreActionsBuilder = ImmutableSet.builder();
ClassPath classPath = ClassPath.from(Action.class.getClassLoader());
ImmutableSet<ClassPath.ClassInfo> infos = classPath.getTopLevelClassesRecursive(Action.class.getPackage().getName());
for (ClassPath.ClassInfo info : infos) {
Class clazz = info.load();
if (Action.class.isAssignableFrom(clazz)) {
if (!Modifier.isAbstract(clazz.getModifiers())) {
Field field = null;
try {
field = clazz.getField("INSTANCE");
} catch (NoSuchFieldException nsfe) {
fail("every action should have a static field called INSTANCE, missing in " + clazz.getName());
}
assertThat("every action should have a static field called INSTANCE, present but not static in " + clazz.getName(),
Modifier.isStatic(field.getModifiers()), is(true));
coreActionsBuilder.add(((Action) field.get(null)).name());
}
}
}
return coreActionsBuilder.build();
}
}

View File

@ -50,9 +50,6 @@ indices:monitor/segments
indices:monitor/settings/get indices:monitor/settings/get
indices:monitor/stats indices:monitor/stats
indices:monitor/status indices:monitor/status
indices:data/benchmark/abort
indices:data/benchmark/start
indices:data/benchmark/status
indices:data/read/count indices:data/read/count
indices:data/read/exists indices:data/read/exists
indices:data/read/explain indices:data/read/explain

View File

@ -0,0 +1,79 @@
cluster:admin/nodes/restart[n]
cluster:admin/nodes/shutdown[n]
cluster:admin/snapshot/status[nodes]
cluster:admin/snapshot/status[nodes][n]
cluster:monitor/nodes/hot_threads[n]
cluster:monitor/nodes/info[n]
cluster:monitor/nodes/stats[n]
cluster:monitor/stats[n]
indices:admin/analyze[s]
indices:admin/cache/clear[s]
indices:admin/flush[s]
indices:admin/mappings/fields/get[index][s]
indices:admin/optimize[s]
indices:admin/refresh[s]
indices:admin/validate/query[s]
indices:data/read/count[s]
indices:data/read/exists[s]
indices:data/read/explain[s]
indices:data/read/get[s]
indices:data/read/mget[shard][s]
indices:data/read/mpercolate[shard][s]
indices:data/read/mtv[shard][s]
indices:data/read/percolate[s]
indices:data/read/search[clear_scroll_contexts]
indices:data/read/search[free_context/scroll]
indices:data/read/search[free_context]
indices:data/read/search[phase/dfs]
indices:data/read/search[phase/fetch/id/scroll]
indices:data/read/search[phase/fetch/id]
indices:data/read/search[phase/query+fetch/scroll]
indices:data/read/search[phase/query+fetch]
indices:data/read/search[phase/query/id]
indices:data/read/search[phase/query/query+fetch]
indices:data/read/search[phase/query/scroll]
indices:data/read/search[phase/query]
indices:data/read/search[phase/scan/scroll]
indices:data/read/search[phase/scan]
indices:data/read/suggest[s]
indices:data/read/tv[s]
indices:data/write/bulk[s]
indices:data/write/bulk[s][r]
indices:data/write/delete/by_query[s]
indices:data/write/delete/by_query[s][r]
indices:data/write/delete[r]
indices:data/write/delete[s]
indices:data/write/delete[s][r]
indices:data/write/index[r]
indices:monitor/recovery[s]
indices:monitor/segments[s]
indices:monitor/stats[s]
indices:monitor/status[s]
internal:cluster/mapping_updated
internal:cluster/node/index/deleted
internal:cluster/node/index_store/deleted
internal:cluster/node/mapping/refresh
internal:cluster/nodes/indices/shard/store
internal:cluster/nodes/indices/shard/store[n]
internal:cluster/shard/failure
internal:cluster/shard/started
internal:cluster/snapshot/update_restore
internal:cluster/snapshot/update_snapshot
internal:discovery/zen/fd/master_ping
internal:discovery/zen/fd/ping
internal:discovery/zen/join
internal:discovery/zen/join/validate
internal:discovery/zen/leave
internal:discovery/zen/publish
internal:discovery/zen/rejoin
internal:discovery/zen/unicast
internal:discovery/zen/unicast_gte_1_4
internal:index/shard/exists
internal:index/shard/recovery/clean_files
internal:index/shard/recovery/file_chunk
internal:index/shard/recovery/filesInfo
internal:index/shard/recovery/finalize
internal:index/shard/recovery/prepare_translog
internal:index/shard/recovery/start_recovery
internal:index/shard/recovery/translog_ops
internal:river/state/publish