use of com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId in project conquery by bakdata.
the class AbstractQueryEngineTest method executeTest.
@Override
public void executeTest(StandaloneSupport standaloneSupport) throws IOException {
Query query = getQuery();
assertThat(standaloneSupport.getValidator().validate(query)).describedAs("Query Validation Errors").isEmpty();
log.info("{} QUERY INIT", getLabel());
final User testUser = standaloneSupport.getTestUser();
final ManagedExecutionId executionId = IntegrationUtils.assertQueryResult(standaloneSupport, query, -1, ExecutionState.DONE, testUser, 201);
final ManagedQuery execution = (ManagedQuery) standaloneSupport.getMetaStorage().getExecution(executionId);
// check result info size
List<ResultInfo> resultInfos = execution.getResultInfos();
assertThat(execution.streamResults().flatMap(EntityResult::streamValues)).as("Should have same size as result infos").allSatisfy(v -> assertThat(v).hasSameSizeAs(resultInfos));
// Get the actual response and compare with expected result.
final Response csvResponse = standaloneSupport.getClient().target(HierarchyHelper.hierarchicalPath(standaloneSupport.defaultApiURIBuilder(), ResultCsvResource.class, "getAsCsv").buildFromMap(Map.of(DATASET, standaloneSupport.getDataset().getName(), QUERY, execution.getId().toString()))).queryParam("pretty", false).request(AdditionalMediaTypes.CSV).acceptLanguage(Locale.ENGLISH).get();
List<String> actual = In.stream(((InputStream) csvResponse.getEntity())).readLines();
ResourceFile expectedCsv = getExpectedCsv();
List<String> expected = In.stream(expectedCsv.stream()).readLines();
assertThat(actual).as("Results for %s are not as expected.", this).containsExactlyInAnyOrderElementsOf(expected);
// check that getLastResultCount returns the correct size
if (execution.streamResults().noneMatch(MultilineEntityResult.class::isInstance)) {
assertThat(execution.getLastResultCount()).as("Result count for %s is not as expected.", this).isEqualTo(expected.size() - 1);
}
log.info("INTEGRATION TEST SUCCESSFUL {} {} on {} rows", getClass().getSimpleName(), this, expected.size());
}
use of com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId in project conquery by bakdata.
the class StoredQueriesProcessorTest method mockUser.
private static User mockUser(int id, List<ManagedExecutionId> allowedQueryIds) {
final User user = new User("user" + id, null, STORAGE);
STORAGE.addUser(user);
for (ManagedExecutionId queryId : allowedQueryIds) {
user.addPermission(ExecutionPermission.onInstance(AbilitySets.QUERY_CREATOR, queryId));
}
return user;
}
use of com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId in project conquery by bakdata.
the class PermissionCleanupTask method deleteQueryPermissionsWithMissingRef.
/**
* Deletes permission that reference non-existing executions.
*
* @return The number of deleted permissions.
*/
public static int deleteQueryPermissionsWithMissingRef(MetaStorage storage, Iterable<? extends PermissionOwner<?>> owners) {
int countDeleted = 0;
// Do the loop-di-loop
for (PermissionOwner<?> owner : owners) {
Set<ConqueryPermission> permissions = owner.getPermissions();
for (Permission permission : permissions) {
WildcardPermission wpermission = getAsWildcardPermission(permission);
if (wpermission == null) {
continue;
}
if (!wpermission.getDomains().contains(ExecutionPermission.DOMAIN.toLowerCase())) {
// Skip Permissions that do not reference an Execution/Query
continue;
}
// Handle multiple references to instances
Set<String> validRef = new HashSet<>();
for (String sId : wpermission.getInstances()) {
ManagedExecutionId mId = ManagedExecutionId.Parser.INSTANCE.parse(sId);
if (storage.getExecution(mId) != null) {
// Execution exists -- it is a valid reference
validRef.add(mId.toString());
}
}
if (!validRef.isEmpty()) {
if (wpermission.getInstances().size() == validRef.size()) {
// All are valid, nothing changed proceed with the next permission
continue;
}
// Create a new Permission that only contains valid references
WildcardPermission reducedPermission = new WildcardPermission(List.of(wpermission.getDomains(), wpermission.getAbilities(), validRef), wpermission.getCreationTime());
owner.addPermission(reducedPermission);
}
// Delete the old permission that containes both valid and invalid references
owner.removePermission(wpermission);
countDeleted++;
}
}
return countDeleted;
}
use of com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId in project conquery by bakdata.
the class QueryProcessor method patchQuery.
public void patchQuery(Subject subject, ManagedExecution<?> execution, MetaDataPatch patch) {
log.info("Patching {} ({}) with patch: {}", execution.getClass().getSimpleName(), execution, patch);
patch.applyTo(execution, storage, subject);
storage.updateExecution(execution);
// TODO remove this, since we don't translate anymore
// Patch this query in other datasets
List<Dataset> remainingDatasets = datasetRegistry.getAllDatasets();
remainingDatasets.remove(execution.getDataset());
for (Dataset dataset : remainingDatasets) {
ManagedExecutionId id = new ManagedExecutionId(dataset.getId(), execution.getQueryId());
final ManagedExecution<?> otherExecution = storage.getExecution(id);
if (otherExecution == null) {
continue;
}
log.trace("Patching {} ({}) with patch: {}", execution.getClass().getSimpleName(), id, patch);
patch.applyTo(otherExecution, storage, subject);
storage.updateExecution(execution);
}
}
use of com.bakdata.conquery.models.identifiable.ids.specific.ManagedExecutionId in project conquery by bakdata.
the class QueryProcessor method postQuery.
/**
* Creates a query for all datasets, then submits it for execution on the
* intended dataset.
*/
public ManagedExecution<?> postQuery(Dataset dataset, QueryDescription query, Subject subject) {
log.info("Query posted on Dataset[{}] by User[{{}].", dataset.getId(), subject.getId());
// This maps works as long as we have query visitors that are not configured in anyway.
// So adding a visitor twice would replace the previous one but both would have yielded the same result.
// For the future a better data structure might be desired that also regards similar QueryVisitors of different configuration
ClassToInstanceMap<QueryVisitor> visitors = MutableClassToInstanceMap.create();
query.addVisitors(visitors);
// Initialize checks that need to traverse the query tree
visitors.putInstance(QueryUtils.OnlyReusingChecker.class, new QueryUtils.OnlyReusingChecker());
visitors.putInstance(NamespacedIdentifiableCollector.class, new NamespacedIdentifiableCollector());
final String primaryGroupName = AuthorizationHelper.getPrimaryGroup(subject, storage).map(Group::getName).orElse("none");
visitors.putInstance(ExecutionMetrics.QueryMetricsReporter.class, new ExecutionMetrics.QueryMetricsReporter(primaryGroupName));
// Chain all Consumers
Consumer<Visitable> consumerChain = QueryUtils.getNoOpEntryPoint();
for (QueryVisitor visitor : visitors.values()) {
consumerChain = consumerChain.andThen(visitor);
}
// Apply consumers to the query tree
query.visit(consumerChain);
query.authorize(subject, dataset, visitors);
// After all authorization checks we can now use the actual subject to invoke the query and do not to bubble down the Userish in methods
ExecutionMetrics.reportNamespacedIds(visitors.getInstance(NamespacedIdentifiableCollector.class).getIdentifiables(), primaryGroupName);
ExecutionMetrics.reportQueryClassUsage(query.getClass(), primaryGroupName);
final Namespace namespace = datasetRegistry.get(dataset.getId());
final ExecutionManager executionManager = namespace.getExecutionManager();
// If this is only a re-executing query, try to execute the underlying query instead.
{
final Optional<ManagedExecutionId> executionId = visitors.getInstance(QueryUtils.OnlyReusingChecker.class).getOnlyReused();
final Optional<ManagedExecution<?>> execution = executionId.map(id -> tryReuse(query, id, datasetRegistry, config, executionManager, subject.getUser()));
if (execution.isPresent()) {
return execution.get();
}
}
// Execute the query
return executionManager.runQuery(datasetRegistry, query, subject.getUser(), dataset, config);
}
Aggregations