1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 package main // import "github.com/apache/arrow/go/v6/arrow/ipc/cmd/arrow-json-integration-test"
24 "github.com/apache/arrow/go/v6/arrow"
25 "github.com/apache/arrow/go/v6/arrow/array"
26 "github.com/apache/arrow/go/v6/arrow/arrio"
27 "github.com/apache/arrow/go/v6/arrow/internal/arrjson"
28 "github.com/apache/arrow/go/v6/arrow/internal/testing/types"
29 "github.com/apache/arrow/go/v6/arrow/ipc"
30 "golang.org/x/xerrors"
34 log.SetPrefix("arrow-json: ")
38 arrowPath = flag.String("arrow", "", "path to ARROW file")
39 jsonPath = flag.String("json", "", "path to JSON file")
40 mode = flag.String("mode", "VALIDATE", "mode of integration testing tool (ARROW_TO_JSON, JSON_TO_ARROW, VALIDATE)")
41 verbose = flag.Bool("verbose", true, "enable/disable verbose mode")
46 err := runCommand(*jsonPath, *arrowPath, *mode, *verbose)
52 func runCommand(jsonName, arrowName, mode string, verbose bool) error {
53 arrow.RegisterExtensionType(types.NewUUIDType())
56 return xerrors.Errorf("must specify json file name")
60 return xerrors.Errorf("must specify arrow file name")
65 return cnvToJSON(arrowName, jsonName, verbose)
67 return cnvToARROW(arrowName, jsonName, verbose)
69 return validate(arrowName, jsonName, verbose)
71 return xerrors.Errorf("unknown command %q", mode)
77 func cnvToJSON(arrowName, jsonName string, verbose bool) error {
78 r, err := os.Open(arrowName)
80 return xerrors.Errorf("could not open ARROW file %q: %w", arrowName, err)
84 w, err := os.Create(jsonName)
86 return xerrors.Errorf("could not create JSON file %q: %w", jsonName, err)
90 rr, err := ipc.NewFileReader(r)
92 return xerrors.Errorf("could not open ARROW file reader from file %q: %w", arrowName, err)
97 log.Printf("found schema:\n%v\n", rr.Schema())
100 ww, err := arrjson.NewWriter(w, rr.Schema())
102 return xerrors.Errorf("could not create JSON encoder: %w", err)
106 n, err := arrio.Copy(ww, rr)
108 return xerrors.Errorf("could not convert ARROW file reader data to JSON data: %w", err)
111 if got, want := n, int64(rr.NumRecords()); got != want {
112 return xerrors.Errorf("invalid number of records copied (got=%d, want=%d", got, want)
117 return xerrors.Errorf("could not close JSON encoder %q: %w", jsonName, err)
122 return xerrors.Errorf("could not close JSON file %q: %w", jsonName, err)
128 func cnvToARROW(arrowName, jsonName string, verbose bool) error {
129 r, err := os.Open(jsonName)
131 return xerrors.Errorf("could not open JSON file %q: %w", jsonName, err)
135 w, err := os.Create(arrowName)
137 return xerrors.Errorf("could not create ARROW file %q: %w", arrowName, err)
141 rr, err := arrjson.NewReader(r)
143 return xerrors.Errorf("could not open JSON file reader from file %q: %w", jsonName, err)
147 log.Printf("found schema:\n%v\n", rr.Schema())
150 ww, err := ipc.NewFileWriter(w, ipc.WithSchema(rr.Schema()))
152 return xerrors.Errorf("could not create ARROW file writer: %w", err)
156 n, err := arrio.Copy(ww, rr)
158 return xerrors.Errorf("could not convert JSON data to ARROW data: %w", err)
161 if got, want := n, int64(rr.NumRecords()); got != want {
162 return xerrors.Errorf("invalid number of records copied (got=%d, want=%d", got, want)
167 return xerrors.Errorf("could not close ARROW file writer %q: %w", arrowName, err)
172 return xerrors.Errorf("could not close ARROW file %q: %w", arrowName, err)
178 func validate(arrowName, jsonName string, verbose bool) error {
179 jr, err := os.Open(jsonName)
181 return xerrors.Errorf("could not open JSON file %q: %w", jsonName, err)
185 jrr, err := arrjson.NewReader(jr)
187 return xerrors.Errorf("could not open JSON file reader from file %q: %w", jsonName, err)
190 ar, err := os.Open(arrowName)
192 return xerrors.Errorf("could not open ARROW file %q: %w", arrowName, err)
196 arr, err := ipc.NewFileReader(ar)
198 return xerrors.Errorf("could not open ARROW file reader from file %q: %w", arrowName, err)
202 if !arr.Schema().Equal(jrr.Schema()) {
204 log.Printf("JSON schema:\n%v\nArrow schema:\n%v\n", arr.Schema(), jrr.Schema())
206 return xerrors.Errorf("schemas did not match")
209 for i := 0; i < arr.NumRecords(); i++ {
210 arec, err := arr.Read()
212 return xerrors.Errorf("could not read record %d from ARROW file: %w", i, err)
214 jrec, err := jrr.Read()
216 return xerrors.Errorf("could not read record %d from JSON file: %w", i, err)
218 if !array.RecordApproxEqual(jrec, arec) {
219 return xerrors.Errorf("record batch %d did not match\nJSON:\n%v\nARROW:\n%v\n",
225 if jn, an := jrr.NumRecords(), arr.NumRecords(); jn != an {
226 return xerrors.Errorf("different number of record batches: %d (JSON) vs %d (Arrow)", jn, an)