Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check declaration namespace against resource path #18

Open
jangalinski opened this issue Feb 14, 2024 · 1 comment
Open

Check declaration namespace against resource path #18

jangalinski opened this issue Feb 14, 2024 · 1 comment
Labels
Type: enhancement New feature or request

Comments

@jangalinski
Copy link
Contributor

Scenario

Avro declaration files (avsc, avpr) do not have to follow the java package conventions, they are just files. In practice it proved to be useful to apply the package/path conventions for structuring avro files (so foo.bar.MySchema is declared in file /foo/bar/MySchema.avsc).

Wanted Behaviour

On AvroParser level I want to configure (boolean switch) whether the package convention should be applied. If so, parsing the file /foo/bar/MySchema.avsc should fail with an exception if the record inside does not have the FQN foo.bar.MySchema.

@jangalinski jangalinski added the Type: enhancement New feature or request label Feb 14, 2024
@jangalinski
Copy link
Contributor Author

jangalinski commented Feb 14, 2024

Existing example code for such an exception:

/**
 * [AvroRuntimeException] expressing the declared canonical name in the actual resource does not match the path of the resource.
 */
class AvroDeclarationMismatchException(actual: AvroDeclarationFqn, expected: AvroDeclarationFqn) :
  AvroRuntimeException("violation of package-path convention: found declaration fqn='${actual}' but was loaded from path='${expected.path}'")

existing example code for the validation:

  /**
   * An avro declaration file should have a path that matches its canonicalName, the same way a java file has to
   * be defined in the correct package.
   * @throws AvroDeclarationMismatchException
   */
  @Throws(AvroDeclarationMismatchException::class)
  fun verifyPackagePathConvention(actual: GenericAvroDeclarationFqn, expected: GenericAvroDeclarationFqn): Unit = try {
    require(actual == expected)
  } catch (e: Exception) {
    throw AvroDeclarationMismatchException(actual, expected)
  }

possible test

    val cn = TestFixtures.fqnBankAccountCreated
    val origFqn = schema(cn.namespace, cn.name)
    val origSchema = origFqn.fromResource("avro")

    // we write the content to the wrong path "foo/bar"
    val file = origSchema.writeToDirectory(tmpDir, Path("foo/bar/BankAccountCreated.avsc"))
    assertThat(file).exists()
    assertThat(file).isFile

    val fqnWithWrongNamespace = SchemaFqn(namespace = Namespace("foo.bar"), name = Name("BankAccountCreated"))

    assertThatThrownBy {
      fqnWithWrongNamespace.fromDirectory(tmpDir)
    }.isInstanceOf(AvroDeclarationMismatchException::class.java)
      .hasMessageContaining("violation of package-path convention: found declaration fqn='lib.test.event.BankAccountCreated' but was loaded from path='foo/bar/BankAccountCreated.avsc'")

    // if we disable the check, it can be loaded
    val ignoreMismatchSchema = fqnWithWrongNamespace.fromDirectory(tmpDir, false)
    assertThat(ignoreMismatchSchema).isEqualTo(origSchema)
    
    ///
    
        assertThatThrownBy {
      AvroKotlin.verifyPackagePathConvention(
        SchemaFqn(Namespace("foo"), Name("Baz")),
        SchemaFqn(Namespace("foo.bar"), Name("Baz"))
      )
    }.isInstanceOf(AvroDeclarationMismatchException::class.java)
      .hasMessage("violation of package-path convention: found declaration fqn='foo.Baz' but was loaded from path='foo/bar/Baz.avsc'")


@Test
  fun `package convention mismatch`() {
    val namespace = "com.acme.test"
    val name = "Foo"

    val fqn = SchemaFqn(Namespace(namespace + ".foo"), Name(name))
    val schema = simpleStringValueSchema(Namespace(namespace), Name(name))

    val declaration = SchemaDeclaration(fqn, schema)

    assertThat(declaration.contentFqn.namespace.value).isEqualTo(namespace)
    assertThat(declaration.contentFqn.name.value).isEqualTo(name)
    assertThat(declaration.contentFqn.fileExtension).isEqualTo(AvroKotlin.Constants.EXTENSION_SCHEMA)

    assertThatThrownBy { declaration.verifyPackageConvention(true) }
      .isInstanceOf(AvroDeclarationMismatchException::class.java)
  }
  @Test
  fun `violating package convention`() {
    val namespace = "com.acme.test"
    val name = "Foo"

    val differentLocation = SchemaFqn(Namespace("foo"), Name("Bar"))
    val schema = simpleStringValueSchema(Namespace(namespace), Name(name))

    val declaration = SchemaDeclaration(differentLocation, schema)

    assertThatThrownBy { declaration.verifyPackageConvention() }
      .isInstanceOf(AvroDeclarationMismatchException::class.java)

  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant