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

[CALCITE-5964] Add test case checking that connection.getMetaData().getTables() handles responses with different signature shapes. #227

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

olivrlee
Copy link
Contributor

Also adding in Type.CLASS to ConnectionProperty.java and the associated getters.

…etTables() handles responses with different signature shapes.

Also adding in Type.CLASS to ConnectionProperty.java and the associated getters.
@olivrlee olivrlee marked this pull request as ready for review September 11, 2023 23:45

/** Returns the class value of this property. Throws if not set and no
* default. */
public Class<?> getClazz(Class<?> clazz, Class<?> defaultValue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Java convention uses clazz because class is a keyword. getClass is not a keyword. Just call this getClass. Same goes for all other names that contain the word "class" but are not keywords.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a small chance for confusion with Object.getClass(). So, I would recommend calling it getType.

@@ -434,6 +447,30 @@ public T apply(ConnectionProperty connectionProperty, String s) {
}
};
}

public static <T> Converter<T> clazzConverter(final T clazz,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T can be narrowed to Class<T>, since there's only 1 callsite for this function and it will always pass in a Class<X> for some X. That would also make the variable name less confusing.

I suppose that would make this a Converter<Class<?>>. You may want to add another type variable for defaultClass.

@@ -388,6 +388,32 @@ public MetaColumn(
public String getName() {
return columnName;
}
public static String[] getColumnNames() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well link to some documentation: https://docs.oracle.com/en/java/javase/20/docs/api/java.sql/java/sql/DatabaseMetaData.html#getColumns(java.lang.String,java.lang.String,java.lang.String,java.lang.String)

Also add a comment explaining why anybody might want to override this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's static so it can't be overridden, the reader thinks. The fact that the caller is using reflection to find and invoke it could definitely do with some commentary, if that is indeed the best way for the caller to get this information.

+ "[\"PUBLIC\",\"SCOTT\",\"EMP\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,\"EXTRA_LABEL2\"],"
+ "[\"PUBLIC\",\"SCOTT\",\"BONUS\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,\"EXTRA_LABEL3\"],"
+ "[\"PUBLIC\",\"SCOTT\",\"SALGRADE\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,null]]},"
+ "\"updateCount\":-1,\"rpcMetadata\":null}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This JSON blob is impenetrable. How did you produce this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran another test within Avatica and took that json blob and modified it
What does 'impenetrable' mean here?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to read this data fixture and understand its direct relationship with assertions in tests.

There's also the usual problem with mocking - how do you keep your mocks in sync with the real implementation. When Avatica changes its response, tests depending on this fixture will go stale without further notice and there is no forcing function to cause them to be updated until or unless a regression occurs. But this problem is hard to solve without designing for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So one thing to note is that this test really just shows that whatever Signature comes in (different columns, different orders), Avatica is able to handle the different shapes and read them in the supplied order.
It doesn't test whether the real implementation is providing a correct response in the right order. That part should be up to the implementation.

Maybe that point wasn't clear by this additional test, perhaps I should shorten the JSON to contain fewer columns and add a comment stating that the point is that the signature column order matches up with the resultset columns?

@@ -127,6 +127,21 @@ private Connection getMockConnection() {
connection.close();
}

@Test public void testTablesAdditionalColumns() throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced of the usefulness of this test. Which part of the production code is actually being exercised? Kinda looks like we're just stubbing a mock, then testing that we stubbed it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It mocks getting the response, but it actually tests the client code in RemoteMeta that handles the response and parses the signature into the ResultSet.

@@ -388,6 +388,32 @@ public MetaColumn(
public String getName() {
return columnName;
}
public static String[] getColumnNames() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's static so it can't be overridden, the reader thinks. The fact that the caller is using reflection to find and invoke it could definitely do with some commentary, if that is indeed the best way for the caller to get this information.

+ "[\"PUBLIC\",\"SCOTT\",\"EMP\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,\"EXTRA_LABEL2\"],"
+ "[\"PUBLIC\",\"SCOTT\",\"BONUS\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,\"EXTRA_LABEL3\"],"
+ "[\"PUBLIC\",\"SCOTT\",\"SALGRADE\",\"TABLE\",null,null,null,null,null,null,\"MEMORY\",false,null,null]]},"
+ "\"updateCount\":-1,\"rpcMetadata\":null}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to read this data fixture and understand its direct relationship with assertions in tests.

There's also the usual problem with mocking - how do you keep your mocks in sync with the real implementation. When Avatica changes its response, tests depending on this fixture will go stale without further notice and there is no forcing function to cause them to be updated until or unless a regression occurs. But this problem is hard to solve without designing for it.

@F21 F21 force-pushed the main branch 2 times, most recently from b97b819 to 4c0999b Compare November 28, 2023 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants