or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-org-apache-flink--flink-architecture-tests-test

Architecture testing framework for Apache Flink test code using ArchUnit

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.apache.flink/flink-architecture-tests-test@2.1.x

To install, run

npx @tessl/cli install tessl/maven-org-apache-flink--flink-architecture-tests-test@2.1.0

index.mddocs/

Flink Architecture Tests - Test

Flink Architecture Tests - Test provides architectural testing rules specifically designed for Apache Flink's test code infrastructure. Built on ArchUnit, it enables enforcement of architectural rules and coding standards within Flink's testing ecosystem, helping maintain code quality and architectural integrity across Flink's extensive test suite.

Package Information

  • Package Name: flink-architecture-tests-test
  • Package Type: maven
  • Language: Java
  • Group ID: org.apache.flink
  • Artifact ID: flink-architecture-tests-test
  • Installation: Add as dependency in Maven pom.xml
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-architecture-tests-test</artifactId>
    <version>2.1.0</version>
    <scope>test</scope>  
</dependency>

Core Imports

import org.apache.flink.architecture.TestCodeArchitectureTestBase;
import org.apache.flink.architecture.rules.ITCaseRules;
import org.apache.flink.architecture.rules.BanJunit4Rules;
import org.apache.flink.architecture.common.Conditions;
import org.apache.flink.architecture.common.JavaFieldPredicates;
import org.apache.flink.architecture.common.Predicates;
import org.apache.flink.architecture.common.ImportOptions;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.core.importer.ImportOption;

Basic Usage

Setting up Architectural Tests in a Flink Submodule

package org.apache.flink.architecture;

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.core.importer.ImportOption;
import org.apache.flink.architecture.TestCodeArchitectureTestBase;
import org.apache.flink.architecture.common.ImportOptions;

@AnalyzeClasses(
    packages = {"org.apache.flink.your.module"}, 
    importOptions = {
        ImportOption.OnlyIncludeTests.class,
        ImportOptions.ExcludeScalaImportOption.class,
        ImportOptions.ExcludeShadedImportOption.class
    }
)
public class TestCodeArchitectureTest {
    
    // Include common architectural tests from the base
    @ArchTest 
    public static final ArchTests COMMON_TESTS = 
        ArchTests.in(TestCodeArchitectureTestBase.class);
}

Configuration Files Setup

Create archunit.properties in src/test/resources/:

# Controls if the violation store is writable (enables updating existing violations)
freeze.store.default.allowStoreUpdate=true

# Path to store violations relative to project root
freeze.store.default.path=archunit-violations

# Allow creation of new violation stores (uncomment when setting up new tests)
# freeze.store.default.allowStoreCreation=true

# Re-freeze all violations to current state (uncomment for rule changes)
# freeze.refreeze=true

Create log4j2-test.properties in src/test/resources/ for logging configuration during tests:

# Set root logger to OFF to prevent flooding build logs during architectural testing
rootLogger.level=OFF

Architecture

Flink Architecture Tests - Test is built around several key components:

  • Base Test Class: TestCodeArchitectureTestBase provides a central setup for common architectural tests
  • Rule Collections: Modular rule classes (ITCaseRules, BanJunit4Rules) that group related architectural constraints
  • Utility Classes: Base utility classes (Conditions, JavaFieldPredicates, Predicates) for building custom rules
  • Import Options: Custom import filtering (ImportOptions) to exclude Scala and shaded classes from analysis
  • ArchUnit Integration: Built on top of ArchUnit framework for Java architectural testing
  • Violation Storage: Freezing mechanism to track and manage architectural violations over time
  • Modular Execution: Rules are executed in individual submodules rather than centrally

Capabilities

Base Test Class Integration

Central setup class that provides common architectural tests for all Flink submodules.

public class TestCodeArchitectureTestBase {
    @ArchTest 
    public static final ArchTests ITCASE = ArchTests.in(ITCaseRules.class);
}

Use this class to include standard architectural tests in your submodule:

import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import org.apache.flink.architecture.TestCodeArchitectureTestBase;

public class TestCodeArchitectureTest {
    @ArchTest 
    public static final ArchTests COMMON_TESTS = 
        ArchTests.in(TestCodeArchitectureTestBase.class);
}

Integration Test Rules

Enforces naming conventions and MiniCluster resource usage for integration tests.

public class ITCaseRules {
    @ArchTest
    public static final ArchRule INTEGRATION_TEST_ENDING_WITH_ITCASE;
    
    @ArchTest  
    public static final ArchRule ITCASE_USE_MINICLUSTER;
}

INTEGRATION_TEST_ENDING_WITH_ITCASE: Ensures that classes inheriting from AbstractTestBase have names ending with "ITCase".

ITCASE_USE_MINICLUSTER: Validates that ITCase tests use appropriate MiniCluster resources. Has different requirements for runtime vs non-runtime packages:

For runtime packages (org.apache.flink.runtime.*):

  • Must use InternalMiniClusterExtension for JUnit 5
  • Must use MiniClusterWithClientResource for JUnit 4

For non-runtime packages:

  • Must use MiniClusterExtension for JUnit 5
  • Must use MiniClusterWithClientResource for JUnit 4

JUnit 5 examples:

// For runtime packages
@RegisterExtension
public static final InternalMiniClusterExtension MINI_CLUSTER_RESOURCE =
        new InternalMiniClusterExtension(
                new MiniClusterResourceConfiguration.Builder()
                        .setConfiguration(getFlinkConfiguration())
                        .build());

// For non-runtime packages
@RegisterExtension
public static final MiniClusterExtension MINI_CLUSTER_RESOURCE =
        new MiniClusterExtension(
                new MiniClusterResourceConfiguration.Builder()
                        .setConfiguration(getFlinkConfiguration())
                        .build());

// Alternative annotation-based approach
@ExtendWith(MiniClusterExtension.class)
public class MyITCase {
    // test methods
}

JUnit 4 examples (legacy):

@Rule
public final MiniClusterWithClientResource miniClusterResource =
        new MiniClusterWithClientResource(
                new MiniClusterResourceConfiguration.Builder()
                        .setNumberTaskManagers(1)
                        .setNumberSlotsPerTaskManager(PARALLELISM)
                        .build());

@ClassRule
public static final MiniClusterWithClientResource miniClusterResource =
        new MiniClusterWithClientResource(
                new MiniClusterResourceConfiguration.Builder()
                        .setNumberTaskManagers(1)
                        .setNumberSlotsPerTaskManager(PARALLELISM)
                        .build());

JUnit 4 Migration Rules

Enforces migration from JUnit 4 to JUnit 5 by preventing new JUnit 4 dependencies.

public class BanJunit4Rules {
    @ArchTest
    public static final ArchRule NO_NEW_ADDED_JUNIT4_TEST_RULE;
}

NO_NEW_ADDED_JUNIT4_TEST_RULE: Prevents classes in org.apache.flink.. packages from depending on JUnit 4 classes (junit, org.junit packages). Uses freezing mechanism to track existing violations while preventing new ones.

Utility Classes for Custom Rules

Core utility classes from flink-architecture-tests-base for building custom architectural rules.

Conditions

Generic conditions for testing architectural properties.

public class Conditions {
    /**
     * Creates condition to check fulfillment of predicates
     */
    public static <T> ArchCondition<T> fulfill(DescribedPredicate<T> predicate);
    
    /**
     * Tests leaf types of methods (return types, parameter types, exception types)
     */
    public static ArchCondition<JavaMethod> haveLeafTypes(DescribedPredicate<JavaClass> predicate);
    
    /**
     * Tests leaf return types of methods
     */
    public static ArchCondition<JavaMethod> haveLeafReturnTypes();
    
    /**
     * Tests leaf argument types of methods
     */
    public static ArchCondition<JavaMethod> haveLeafArgumentTypes();
    
    /**
     * Tests leaf exception types of methods
     */
    public static ArchCondition<JavaMethod> haveLeafExceptionTypes();
}

JavaFieldPredicates

Predicates for testing Java field properties.

public class JavaFieldPredicates {
    // Field modifier predicates
    public static DescribedPredicate<JavaField> isPublic();
    public static DescribedPredicate<JavaField> isStatic();
    public static DescribedPredicate<JavaField> isNotStatic();
    public static DescribedPredicate<JavaField> isFinal();
    
    // Type matching predicates
    public static DescribedPredicate<JavaField> ofType(Class<?> type);
    public static DescribedPredicate<JavaField> ofType(String typeName);
    public static DescribedPredicate<JavaField> isAssignableTo(Class<?> type);
    
    // Annotation predicates
    public static DescribedPredicate<JavaField> annotatedWith(Class<? extends Annotation> annotationType);
    public static DescribedPredicate<JavaField> annotatedWith(String annotationTypeName);
}

Predicates

Complex field predicates combining multiple constraints.

public class Predicates {
    // Combined field predicates
    public static DescribedPredicate<JavaField> arePublicStaticOfType(Class<?> type);
    public static DescribedPredicate<JavaField> arePublicFinalOfType(Class<?> type);
    public static DescribedPredicate<JavaField> arePublicStaticFinalAssignableTo(Class<?> type);
    
    // Annotation combination predicates
    public static DescribedPredicate<JavaField> arePublicFinalOfTypeWithAnnotation(
            Class<?> type, Class<? extends Annotation> annotationType);
    public static DescribedPredicate<JavaField> arePublicStaticFinalOfTypeWithAnnotation(
            Class<?> type, Class<? extends Annotation> annotationType);
    public static DescribedPredicate<JavaField> areStaticFinalOfTypeWithAnnotation(
            Class<?> type, Class<? extends Annotation> annotationType);
    
    // Utility methods
    public static String getClassSimpleNameFromFqName(String fullyQualifiedName);
    public static <T> DescribedPredicate<T> exactlyOneOf(DescribedPredicate<? super T>... predicates);
}

ImportOptions

Custom import filtering options for ArchUnit class analysis.

public class ImportOptions {
    /**
     * Excludes Scala classes from analysis
     */
    public static class ExcludeScalaImportOption implements ImportOption;
    
    /**
     * Excludes shaded/relocated classes from analysis  
     */
    public static class ExcludeShadedImportOption implements ImportOption;
    
    /**
     * Imports only main classes (excludes test classes)
     */
    public static class MavenMainClassesOnly implements ImportOption;
}

Rule Management Commands

When modifying existing rules, regenerate violation stores:

# Remove existing violation stores
rm -rf `find . -type d -name archunit-violations`

# Regenerate stores with current state
mvn test -Dtest="*TestCodeArchitectureTest*" \
    -DfailIfNoTests=false \
    -Darchunit.freeze.refreeze=true \
    -Darchunit.freeze.store.default.allowStoreCreation=true \
    -Dfast

Types

ArchUnit Core Types

// From ArchUnit framework
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.junit.ArchTests;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaField;
import com.tngtech.archunit.core.domain.JavaMethod;
import com.tngtech.archunit.core.importer.ImportOption;

// Annotation for marking architectural test fields
@interface ArchTest {
}

// Container for multiple architectural tests
class ArchTests {
    static ArchTests in(Class<?> testClass);
}

// Individual architectural rule
interface ArchRule {
    ArchRule allowEmptyShould(boolean allow);
    ArchRule as(String description);
}

// Annotation for specifying which classes to analyze
@interface AnalyzeClasses {
    String[] packages();
    Class<? extends ImportOption>[] importOptions() default {};
}

// Base types for predicates and conditions
interface DescribedPredicate<T> {
    boolean test(T input);
    DescribedPredicate<T> and(DescribedPredicate<? super T> other);
    DescribedPredicate<T> or(DescribedPredicate<? super T> other);
}

interface ArchCondition<T> {
    ArchCondition<T> and(ArchCondition<? super T> condition);
    ArchCondition<T> or(ArchCondition<? super T> condition);
    ArchCondition<T> as(String description);
}

// Import filtering interface
interface ImportOption {
    boolean includes(Location location);
}

Configuration Properties

The package uses ArchUnit's configuration system through archunit.properties:

  • freeze.store.default.allowStoreUpdate: Controls if violation store is writable
  • freeze.store.default.allowStoreCreation: Enables creation of new violation stores
  • freeze.refreeze: Records current state of violations
  • freeze.store.default.path: Path to store violations (default: "archunit-violations")

Error Handling

When architectural tests fail, ArchUnit provides detailed violation reports including:

  • Specific classes that violate the rules
  • Line numbers and method details where applicable
  • Clear descriptions of what constraint was violated
  • Suggestions for fixing the violations

Common failure scenarios:

  • ITCase naming violations: Tests inheriting from AbstractTestBase without "ITCase" suffix
  • Missing MiniCluster resources: ITCase tests without proper cluster setup
  • Wrong MiniCluster type: Runtime packages using MiniClusterExtension instead of InternalMiniClusterExtension
  • JUnit 4 dependencies: New test code depending on legacy JUnit 4 classes
  • Configuration issues: Missing or incorrect archunit.properties setup
  • Freezing violations: Rules that have existing violations must be wrapped in FreezingArchRule.freeze()

Troubleshooting

Violation Store Issues:

  • If tests fail due to missing violation stores, set freeze.store.default.allowStoreCreation=true in archunit.properties
  • To regenerate all violation stores after rule changes, use the freeze.refreeze=true option
  • Violation stores are stored in the archunit-violations directory and should be committed to version control

Rule Freezing Requirements:

  • Rules with existing violations must use FreezingArchRule.freeze() wrapper
  • Frozen rules should have fixed descriptions using .as(String) to reduce maintenance overhead
  • When modifying rule descriptions, regenerate violation stores to prevent false failures

Package-Specific Rule Failures:

  • Runtime package tests must use InternalMiniClusterExtension for JUnit 5
  • Non-runtime package tests must use MiniClusterExtension for JUnit 5
  • Both can use MiniClusterWithClientResource for JUnit 4 compatibility