@@ -26,6 +26,7 @@ import (
2626 "strings"
2727 "testing"
2828
29+ "github.com/apache/iceberg-go"
2930 "github.com/apache/iceberg-go/catalog"
3031 "github.com/apache/iceberg-go/catalog/hadoop"
3132 "github.com/apache/iceberg-go/internal/recipe"
@@ -228,6 +229,82 @@ func (s *HadoopIntegrationSuite) TestDropTableThenListReflects() {
228229 s .Equal ("keep" , tables [0 ][len (tables [0 ])- 1 ])
229230}
230231
232+ // TestGoCreateSparkDescribe creates a table from Go, then asks Spark to
233+ // DESCRIBE it and verifies that Spark sees the expected columns.
234+ func (s * HadoopIntegrationSuite ) TestGoCreateSparkDescribe () {
235+ // Create namespace from Go so the directory is owned by the runner
236+ // process and Go can create table subdirectories inside it.
237+ err := s .cat .CreateNamespace (s .ctx , []string {"describe_ns" }, nil )
238+ s .Require ().NoError (err )
239+
240+ schema := iceberg .NewSchema (1 ,
241+ iceberg.NestedField {ID : 1 , Name : "id" , Type : iceberg .PrimitiveTypes .Int64 , Required : true },
242+ iceberg.NestedField {ID : 2 , Name : "name" , Type : iceberg .PrimitiveTypes .String , Required : false },
243+ )
244+
245+ tbl , err := s .cat .CreateTable (s .ctx , []string {"describe_ns" , "go_created_table" }, schema )
246+ s .Require ().NoError (err )
247+ s .NotNil (tbl )
248+
249+ output := s .sparkSQL ("DESCRIBE TABLE hadoop_test.describe_ns.go_created_table" )
250+ s .Contains (output , "id" )
251+ s .Contains (output , "name" )
252+ }
253+
254+ // TestSparkCreateGoLoad creates a table from Spark, then loads it from
255+ // Go and verifies schema and metadata are consistent.
256+ func (s * HadoopIntegrationSuite ) TestSparkCreateGoLoad () {
257+ // Spark creates both namespace and table — Go only reads here.
258+ s .sparkSQL ("CREATE NAMESPACE IF NOT EXISTS hadoop_test.load_ns" )
259+ s .sparkSQL ("CREATE TABLE hadoop_test.load_ns.spark_created_table (age INT, city STRING) USING iceberg" )
260+
261+ tbl , err := s .cat .LoadTable (s .ctx , []string {"load_ns" , "spark_created_table" })
262+ s .Require ().NoError (err )
263+ s .NotNil (tbl )
264+
265+ fields := tbl .Schema ().Fields ()
266+ fieldNames := make ([]string , len (fields ))
267+ for i , f := range fields {
268+ fieldNames [i ] = f .Name
269+ }
270+
271+ s .Contains (fieldNames , "age" )
272+ s .Contains (fieldNames , "city" )
273+ }
274+
275+ // TestGoCreateSparkSelect creates a table from Go, then runs a SELECT
276+ // from Spark to confirm the table is queryable (should return empty).
277+ func (s * HadoopIntegrationSuite ) TestGoCreateSparkSelect () {
278+ err := s .cat .CreateNamespace (s .ctx , []string {"select_ns" }, nil )
279+ s .Require ().NoError (err )
280+
281+ schema := iceberg .NewSchema (1 ,
282+ iceberg.NestedField {ID : 1 , Name : "value" , Type : iceberg .PrimitiveTypes .Int32 , Required : true },
283+ )
284+
285+ _ , err = s .cat .CreateTable (s .ctx , []string {"select_ns" , "go_select_table" }, schema )
286+ s .Require ().NoError (err )
287+
288+ output := s .sparkSQL ("SELECT * FROM hadoop_test.select_ns.go_select_table" )
289+ s .Contains (output , "value" )
290+ }
291+
292+ // TestGoCheckTableExistsForSparkTable verifies that CheckTableExists
293+ // returns true for a table created by Spark.
294+ func (s * HadoopIntegrationSuite ) TestGoCheckTableExistsForSparkTable () {
295+ // Spark creates both namespace and table — Go only checks existence.
296+ s .sparkSQL ("CREATE NAMESPACE IF NOT EXISTS hadoop_test.exists_ns" )
297+ s .sparkSQL ("CREATE TABLE hadoop_test.exists_ns.spark_exists_table (x INT) USING iceberg" )
298+
299+ exists , err := s .cat .CheckTableExists (s .ctx , []string {"exists_ns" , "spark_exists_table" })
300+ s .Require ().NoError (err )
301+ s .True (exists )
302+
303+ exists , err = s .cat .CheckTableExists (s .ctx , []string {"exists_ns" , "no_such_table" })
304+ s .Require ().NoError (err )
305+ s .False (exists )
306+ }
307+
231308func TestHadoopIntegration (t * testing.T ) {
232309 suite .Run (t , new (HadoopIntegrationSuite ))
233310}
0 commit comments