Repository navigation
Conversation
|
|
||
| // Properly set conversion types even for non-materialized fields | ||
| // (since we're reading all of them anyways) | ||
| for (auto field : scan_options->dataset_schema->fields()) { |
There was a problem hiding this comment.
Unifying the tests led me to discover this, which I think inadvertently fixes a bug I ran into in ARROW-9697 that I hadn't figured out before. There, I found that for CSV fragments to_table(schema=..., columns=[]) would fail when to_table(schema=...) did not fail, because in the former case, the CSV reader would complain about an invalid cast, seemingly ignoring the schema set.
I think this isn't the best solution, however; we should actually be deriving include_columns.
westonpace
left a comment
There was a problem hiding this comment.
This is great. Getting rid of a lot of duplicate code. I still want to review the tests removed but here are some initial thoughts.
| if (column_names.find(field->name()) == column_names.end()) continue; | ||
| convert_options.column_types[field->name()] = field->type(); | ||
| // Only read the requested columns | ||
| if (materialized_fields.find(field->name()) == materialized_fields.end()) continue; |
There was a problem hiding this comment.
Pretty minor nit but maybe move this above convert_options.column_types... so that convert_options.column_types doesn't include columns that are not in convert_options.include_columns.
| namespace dataset { | ||
|
|
||
| class TestCsvFileFormat : public testing::TestWithParam<Compression::type> { | ||
| class ArrowCsvWriterMixin { |
There was a problem hiding this comment.
Naming nit: Not sure mixin is the right term here. When I think mixin I think multiple inheritance. Maybe Strategy? Also, why "ArrowCsv". Are there other CSV writers? Also, maybe there is a way to use composition here? Have an abstract method in FileFormatFixtureMixin that returns a FormatStrategy or something? I know "prefer composition over inheritance" but I don't know if there is a similar "prefer composition over template" guideline 😆
There was a problem hiding this comment.
I originally tried with abstract methods, but then because of the inheritance tree, you'd have to re-implement them in the AbcFileFormatTest and in the AbcFileFormatScanTest fixtures (I had issues when trying to just have the latter inherit the former). Probably there is some combination of superclasses and interfaces that'll make it work but at that point I decided a template was the lesser evil.
| void TestOpenFailureWithRelevantError(FileFormat* format, StatusCode code) { | ||
| std::shared_ptr<Buffer> buf = std::make_shared<Buffer>(util::string_view("")); | ||
| auto result = format->Inspect(FileSource(buf)); | ||
| EXPECT_FALSE(result.ok()); |
There was a problem hiding this comment.
These ok checks seem redundant given we are not testing Result/Status here and you test the code on the next line.
| } | ||
|
|
||
| // Shared test cases | ||
| void TestOpenFailureWithRelevantError(FileFormat* format, StatusCode code) { |
There was a problem hiding this comment.
Rename to TestInspectFailureWithRelevantError? There is no method named Open on FileFormat.
| @@ -199,18 +210,11 @@ TEST_P(TestCsvFileFormat, OpenFailureWithRelevantError) { | |||
| if (GetCompression() != Compression::type::UNCOMPRESSED) { | |||
| GTEST_SKIP() << "File source name is different with compression"; | |||
There was a problem hiding this comment.
Is this really a problem? Compression is just adding to the filename and we are testing with HasSubstr.
| ASSERT_OK(SetProjection(opts_.get(), opts_->dataset_schema->field_names())); | ||
| } | ||
|
|
||
| void SetFilter(Expression filter) { |
There was a problem hiding this comment.
Not for this PR but I feel like there are a number of places where we have to do something like this to maintain implicit invariants. It might be nice to have a ScanOptions cleanup at some point. Change the name so it isn't Options, hide it from the public API, give it more methods (like SetFilter) and private state.
| ASSERT_OK_AND_ASSIGN(supported, format->IsSupported(*source)); | ||
| EXPECT_EQ(supported, true); | ||
| } | ||
| std::shared_ptr<Buffer> TestWrite(FileFormat* format, std::shared_ptr<Schema> schema, |
There was a problem hiding this comment.
Nit: This is more helper function than test. Perhaps rename to WriteToBuffer? Also, we could create a TestWrite here that does...
auto reader = GetRecordBatchReader(schema({field("f64", float64())}));
auto source = GetFileSource(reader.get());
auto written = WriteToBuffer(format_.get(), reader->schema());
AssertBufferEqual(*written, *source->buffer());
...that should be universally applicable.
| auto dataset = std::make_shared<FragmentDataset>(schema, FragmentVector{fragment}); | ||
| ScannerBuilder builder(dataset, opts_); | ||
| ARROW_EXPECT_OK(builder.UseAsync(GetParam().use_async)); | ||
| ARROW_EXPECT_OK(builder.UseThreads(GetParam().use_threads)); |
There was a problem hiding this comment.
Probably no need to set UseThreads here, that will not affect how the FileFormat is interacted with.
| ASSERT_EQ(row_count, GetParam().expected_rows()); | ||
| } | ||
|
|
||
| void TestScanProjected(FileFormat* format) { |
There was a problem hiding this comment.
If projection is applied by the scanner why are we testing it here?
There was a problem hiding this comment.
This is testing whether each format will look at the projection in the ScanOptions and only return the necessary columns to fulfill the projection + filter later on. Notably, CSV didn't properly do that before.
| } | ||
|
|
||
| // Scan the fragment through the scanner. | ||
| RecordBatchIterator Batches(std::shared_ptr<Fragment> fragment) { |
There was a problem hiding this comment.
What does this add to FileFormat testing above and beyond ScanBatches? One could argue that PhysicalBatches is all you need.
There was a problem hiding this comment.
Originally I wanted to have coverage of each file type with the actual scanner (right now we test each format in isolation + the scanner in isolation). But that is overkill as you point out.
There was a problem hiding this comment.
I could be easily convinced either way. I think it's also good to detect potential interaction bugs. I suppose the scanner could do various things with scan options (like the projection issue you mentioned) that aren't so easily exhaustively tested in formats.
There was a problem hiding this comment.
On balance I think I'll refactor this since you plan to add fuller integration tests for datasets which is a better spot to catch more involved things. The test cases here I'll keep, but only to directly test Scan/ScanBatches.
|
Ah, despite all the diffs, no tests should have been removed - only shuffled around or consolidated when they were the same exact test. |
westonpace
left a comment
There was a problem hiding this comment.
Should have been clearer earlier. I just wanted to do a quick pass to make sure that no tests got missed in the refactor. But I can't see any so looks good. I don't think any of my change in this PR or the other are required.
| auto sink = CreateOutputStream(pool); | ||
|
|
||
| ARROW_EXPECT_OK(WriteRecordBatchReader(reader, pool, sink)); | ||
| // XXX the rest of the test may crash if this fails, since out will be nullptr |
There was a problem hiding this comment.
Minor but could the method be changed to return Result so this comment can go away?
|
Thanks for the quick review. I think everything's been addressed. |
This unifies (most of) the tests across Parquet, Feather, and CSV (with carve-outs for particular cases). In particular, this means all formats are now tested in conjunction with async/sync and serial/threaded scanners. Also, a set of common file format tests were refactored out of the individual tests and centralized.