github.com/niko0xdev/gqlgen@v0.17.55-0.20240120102243-2ecff98c3e37/plugin/federation/federation_test.go (about)

     1  package federation
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/require"
     7  
     8  	"github.com/niko0xdev/gqlgen/codegen"
     9  	"github.com/niko0xdev/gqlgen/codegen/config"
    10  )
    11  
    12  func TestWithEntities(t *testing.T) {
    13  	f, cfg := load(t, "testdata/allthethings/gqlgen.yml")
    14  
    15  	require.Equal(t, []string{"ExternalExtension", "Hello", "MoreNesting", "MultiHelloMultiKey", "NestedKey", "VeryNestedKey", "World"}, cfg.Schema.Types["_Entity"].Types)
    16  
    17  	require.Len(t, cfg.Schema.Types["Entity"].Fields, 8)
    18  
    19  	require.Equal(t, "findExternalExtensionByUpc", cfg.Schema.Types["Entity"].Fields[0].Name)
    20  	require.Equal(t, "findHelloByName", cfg.Schema.Types["Entity"].Fields[1].Name)
    21  	// missing on purpose: all @external fields:
    22  	// require.Equal(t, "findMoreNestingByID", cfg.Schema.Types["Entity"].Fields[2].Name)
    23  	require.Equal(t, "findManyMultiHelloMultiKeyByNames", cfg.Schema.Types["Entity"].Fields[2].Name)
    24  	require.Equal(t, "findManyMultiHelloMultiKeyByKey2s", cfg.Schema.Types["Entity"].Fields[3].Name)
    25  	require.Equal(t, "findNestedKeyByIDAndHelloName", cfg.Schema.Types["Entity"].Fields[4].Name)
    26  	require.Equal(t, "findVeryNestedKeyByIDAndHelloNameAndWorldFooAndWorldBarAndMoreWorldFoo", cfg.Schema.Types["Entity"].Fields[5].Name)
    27  	require.Equal(t, "findWorldByFoo", cfg.Schema.Types["Entity"].Fields[6].Name)
    28  	require.Equal(t, "findWorldByBar", cfg.Schema.Types["Entity"].Fields[7].Name)
    29  
    30  	require.NoError(t, f.MutateConfig(cfg))
    31  
    32  	require.Len(t, f.Entities, 7)
    33  
    34  	require.Equal(t, "ExternalExtension", f.Entities[0].Name)
    35  	require.Len(t, f.Entities[0].Resolvers, 1)
    36  	require.Len(t, f.Entities[0].Resolvers[0].KeyFields, 1)
    37  	require.Equal(t, "upc", f.Entities[0].Resolvers[0].KeyFields[0].Definition.Name)
    38  	require.Equal(t, "String", f.Entities[0].Resolvers[0].KeyFields[0].Definition.Type.Name())
    39  
    40  	require.Equal(t, "Hello", f.Entities[1].Name)
    41  	require.Len(t, f.Entities[1].Resolvers, 1)
    42  	require.Len(t, f.Entities[1].Resolvers[0].KeyFields, 1)
    43  	require.Equal(t, "name", f.Entities[1].Resolvers[0].KeyFields[0].Definition.Name)
    44  	require.Equal(t, "String", f.Entities[1].Resolvers[0].KeyFields[0].Definition.Type.Name())
    45  
    46  	require.Equal(t, "MoreNesting", f.Entities[2].Name)
    47  	require.Len(t, f.Entities[2].Resolvers, 0)
    48  
    49  	require.Equal(t, "MultiHelloMultiKey", f.Entities[3].Name)
    50  	require.Len(t, f.Entities[3].Resolvers, 2)
    51  	require.Len(t, f.Entities[3].Resolvers[0].KeyFields, 1)
    52  	require.Len(t, f.Entities[3].Resolvers[1].KeyFields, 1)
    53  	require.Equal(t, "name", f.Entities[3].Resolvers[0].KeyFields[0].Definition.Name)
    54  	require.Equal(t, "String", f.Entities[3].Resolvers[0].KeyFields[0].Definition.Type.Name())
    55  	require.Equal(t, "key2", f.Entities[3].Resolvers[1].KeyFields[0].Definition.Name)
    56  	require.Equal(t, "String", f.Entities[3].Resolvers[1].KeyFields[0].Definition.Type.Name())
    57  
    58  	require.Equal(t, "NestedKey", f.Entities[4].Name)
    59  	require.Len(t, f.Entities[4].Resolvers, 1)
    60  	require.Len(t, f.Entities[4].Resolvers[0].KeyFields, 2)
    61  	require.Equal(t, "id", f.Entities[4].Resolvers[0].KeyFields[0].Definition.Name)
    62  	require.Equal(t, "String", f.Entities[4].Resolvers[0].KeyFields[0].Definition.Type.Name())
    63  	require.Equal(t, "helloName", f.Entities[4].Resolvers[0].KeyFields[1].Definition.Name)
    64  	require.Equal(t, "String", f.Entities[4].Resolvers[0].KeyFields[1].Definition.Type.Name())
    65  
    66  	require.Equal(t, "VeryNestedKey", f.Entities[5].Name)
    67  	require.Len(t, f.Entities[5].Resolvers, 1)
    68  	require.Len(t, f.Entities[5].Resolvers[0].KeyFields, 5)
    69  	require.Equal(t, "id", f.Entities[5].Resolvers[0].KeyFields[0].Definition.Name)
    70  	require.Equal(t, "String", f.Entities[5].Resolvers[0].KeyFields[0].Definition.Type.Name())
    71  	require.Equal(t, "helloName", f.Entities[5].Resolvers[0].KeyFields[1].Definition.Name)
    72  	require.Equal(t, "String", f.Entities[5].Resolvers[0].KeyFields[1].Definition.Type.Name())
    73  	require.Equal(t, "worldFoo", f.Entities[5].Resolvers[0].KeyFields[2].Definition.Name)
    74  	require.Equal(t, "String", f.Entities[5].Resolvers[0].KeyFields[2].Definition.Type.Name())
    75  	require.Equal(t, "worldBar", f.Entities[5].Resolvers[0].KeyFields[3].Definition.Name)
    76  	require.Equal(t, "Int", f.Entities[5].Resolvers[0].KeyFields[3].Definition.Type.Name())
    77  	require.Equal(t, "moreWorldFoo", f.Entities[5].Resolvers[0].KeyFields[4].Definition.Name)
    78  	require.Equal(t, "String", f.Entities[5].Resolvers[0].KeyFields[4].Definition.Type.Name())
    79  
    80  	require.Len(t, f.Entities[5].Requires, 2)
    81  	require.Equal(t, f.Entities[5].Requires[0].Name, "id")
    82  	require.Equal(t, f.Entities[5].Requires[1].Name, "helloSecondary")
    83  
    84  	require.Equal(t, "World", f.Entities[6].Name)
    85  	require.Len(t, f.Entities[6].Resolvers, 2)
    86  	require.Len(t, f.Entities[6].Resolvers[0].KeyFields, 1)
    87  	require.Equal(t, "foo", f.Entities[6].Resolvers[0].KeyFields[0].Definition.Name)
    88  	require.Equal(t, "String", f.Entities[6].Resolvers[0].KeyFields[0].Definition.Type.Name())
    89  	require.Len(t, f.Entities[6].Resolvers[1].KeyFields, 1)
    90  	require.Equal(t, "bar", f.Entities[6].Resolvers[1].KeyFields[0].Definition.Name)
    91  	require.Equal(t, "Int", f.Entities[6].Resolvers[1].KeyFields[0].Definition.Type.Name())
    92  }
    93  
    94  func TestNoEntities(t *testing.T) {
    95  	f, cfg := load(t, "testdata/entities/nokey.yml")
    96  
    97  	err := f.MutateConfig(cfg)
    98  	require.NoError(t, err)
    99  	require.Len(t, f.Entities, 0)
   100  }
   101  
   102  func TestUnusedInterfaceKeyDirective(t *testing.T) {
   103  	f, cfg := load(t, "testdata/interfaces/unused_key.yml")
   104  
   105  	err := f.MutateConfig(cfg)
   106  	require.NoError(t, err)
   107  	require.Len(t, f.Entities, 0)
   108  }
   109  
   110  func TestInterfaceKeyDirective(t *testing.T) {
   111  	f, cfg := load(t, "testdata/interfaces/key.yml")
   112  
   113  	err := f.MutateConfig(cfg)
   114  	require.NoError(t, err)
   115  	require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
   116  	require.Len(t, f.Entities, 2)
   117  }
   118  
   119  func TestInterfaceExtendsDirective(t *testing.T) {
   120  	require.Panics(t, func() {
   121  		load(t, "testdata/interfaces/extends.yml")
   122  	})
   123  }
   124  
   125  func TestEntityInterfaces(t *testing.T) {
   126  	f, cfg := load(t, "testdata/entityinterfaces/interface.yml")
   127  	err := f.MutateConfig(cfg)
   128  
   129  	require.NoError(t, err)
   130  	require.Len(t, f.Entities[0].Resolvers, 1)
   131  	require.Equal(t, "Hello", f.Entities[0].Name)
   132  	require.NotEmpty(t, f.Entities[1].Resolvers)
   133  }
   134  
   135  func TestCodeGeneration(t *testing.T) {
   136  	f, cfg := load(t, "testdata/allthethings/gqlgen.yml")
   137  
   138  	require.Len(t, cfg.Schema.Types["_Entity"].Types, 7)
   139  	require.Len(t, f.Entities, 7)
   140  
   141  	require.NoError(t, f.MutateConfig(cfg))
   142  
   143  	data, err := codegen.BuildData(cfg)
   144  	if err != nil {
   145  		panic(err)
   146  	}
   147  	require.NoError(t, f.GenerateCode(data))
   148  }
   149  
   150  func TestCodeGenerationFederation2(t *testing.T) {
   151  	f, cfg := load(t, "testdata/federation2/federation2.yml")
   152  	err := f.MutateConfig(cfg)
   153  
   154  	require.NoError(t, err)
   155  	require.Equal(t, "ExternalExtension", f.Entities[0].Name)
   156  	require.Len(t, f.Entities[0].Resolvers, 1)
   157  	require.Equal(t, "Hello", f.Entities[1].Name)
   158  	require.Empty(t, f.Entities[1].Resolvers)
   159  	require.Equal(t, "World", f.Entities[2].Name)
   160  	require.Empty(t, f.Entities[2].Resolvers)
   161  
   162  	data, err := codegen.BuildData(cfg)
   163  	if err != nil {
   164  		panic(err)
   165  	}
   166  	require.NoError(t, f.GenerateCode(data))
   167  }
   168  
   169  // This test is to ensure that the input arguments are not
   170  // changed when cfg.OmitSliceElementPointers is false OR true
   171  func TestMultiWithOmitSliceElemPointersCfg(t *testing.T) {
   172  
   173  	staticRepsString := "reps: [HelloByNamesInput]!"
   174  	t.Run("OmitSliceElementPointers true", func(t *testing.T) {
   175  		f, cfg := load(t, "testdata/multi/multi.yml")
   176  		cfg.OmitSliceElementPointers = true
   177  		err := f.MutateConfig(cfg)
   178  		require.NoError(t, err)
   179  		require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
   180  		require.Len(t, f.Entities, 1)
   181  
   182  		entityGraphqlGenerated := false
   183  		for _, source := range cfg.Sources {
   184  			if source.Name != "federation/entity.graphql" {
   185  				continue
   186  			}
   187  			entityGraphqlGenerated = true
   188  			require.Contains(t, source.Input, staticRepsString)
   189  		}
   190  		require.True(t, entityGraphqlGenerated)
   191  	})
   192  
   193  	t.Run("OmitSliceElementPointers false", func(t *testing.T) {
   194  		f, cfg := load(t, "testdata/multi/multi.yml")
   195  		cfg.OmitSliceElementPointers = false
   196  		err := f.MutateConfig(cfg)
   197  		require.NoError(t, err)
   198  		require.Len(t, cfg.Schema.Types["_Entity"].Types, 1)
   199  		require.Len(t, f.Entities, 1)
   200  
   201  		entityGraphqlGenerated := false
   202  		for _, source := range cfg.Sources {
   203  			if source.Name != "federation/entity.graphql" {
   204  				continue
   205  			}
   206  			entityGraphqlGenerated = true
   207  			require.Contains(t, source.Input, staticRepsString)
   208  		}
   209  		require.True(t, entityGraphqlGenerated)
   210  	})
   211  }
   212  
   213  func TestInjectSourceLate(t *testing.T) {
   214  	_, cfg := load(t, "testdata/allthethings/gqlgen.yml")
   215  	entityGraphqlGenerated := false
   216  	for _, source := range cfg.Sources {
   217  		if source.Name != "federation/entity.graphql" {
   218  			continue
   219  		}
   220  		entityGraphqlGenerated = true
   221  		require.Contains(t, source.Input, "union _Entity")
   222  		require.Contains(t, source.Input, "type _Service {")
   223  		require.Contains(t, source.Input, "extend type Query {")
   224  		require.Contains(t, source.Input, "_entities(representations: [_Any!]!): [_Entity]!")
   225  		require.Contains(t, source.Input, "_service: _Service!")
   226  	}
   227  	require.True(t, entityGraphqlGenerated)
   228  
   229  	_, cfg = load(t, "testdata/entities/nokey.yml")
   230  	entityGraphqlGenerated = false
   231  	for _, source := range cfg.Sources {
   232  		if source.Name != "federation/entity.graphql" {
   233  			continue
   234  		}
   235  		entityGraphqlGenerated = true
   236  		require.NotContains(t, source.Input, "union _Entity")
   237  		require.Contains(t, source.Input, "type _Service {")
   238  		require.Contains(t, source.Input, "extend type Query {")
   239  		require.NotContains(t, source.Input, "_entities(representations: [_Any!]!): [_Entity]!")
   240  		require.Contains(t, source.Input, "_service: _Service!")
   241  	}
   242  	require.True(t, entityGraphqlGenerated)
   243  
   244  	_, cfg = load(t, "testdata/schema/customquerytype.yml")
   245  	for _, source := range cfg.Sources {
   246  		if source.Name != "federation/entity.graphql" {
   247  			continue
   248  		}
   249  		require.Contains(t, source.Input, "extend type CustomQuery {")
   250  	}
   251  }
   252  
   253  func load(t *testing.T, name string) (*federation, *config.Config) {
   254  	t.Helper()
   255  
   256  	cfg, err := config.LoadConfig(name)
   257  	require.NoError(t, err)
   258  
   259  	if cfg.Federation.Version == 0 {
   260  		cfg.Federation.Version = 1
   261  	}
   262  
   263  	f := &federation{Version: cfg.Federation.Version}
   264  	cfg.Sources = append(cfg.Sources, f.InjectSourceEarly())
   265  	require.NoError(t, cfg.LoadSchema())
   266  
   267  	if src := f.InjectSourceLate(cfg.Schema); src != nil {
   268  		cfg.Sources = append(cfg.Sources, src)
   269  	}
   270  	require.NoError(t, cfg.LoadSchema())
   271  
   272  	require.NoError(t, cfg.Init())
   273  	return f, cfg
   274  }