mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-09-20 15:09:02 +03:00
cli: expose method to get iconsistent metadata objects
https://github.com/hasura/graphql-engine-mono/pull/1725 GitOrigin-RevId: 68c64369dcc950def19bf773ab1bc95226ebcdd4
This commit is contained in:
parent
614c0dab80
commit
e99c012af6
@ -120,26 +120,20 @@ func (c *ClientCommonMetadataOps) ReplaceMetadata(metadata io.Reader) (io.Reader
|
||||
}
|
||||
|
||||
func (c *ClientCommonMetadataOps) GetInconsistentMetadata() (*hasura.GetInconsistentMetadataResponse, error) {
|
||||
request := hasura.RequestBody{
|
||||
Type: "get_inconsistent_metadata",
|
||||
Args: map[string]string{},
|
||||
}
|
||||
responseBody := new(bytes.Buffer)
|
||||
response, err := c.send(request, responseBody)
|
||||
inconsistentMetadata := new(hasura.GetInconsistentMetadataResponse)
|
||||
responseBody, err := c.GetInconsistentMetadataRaw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("%s", responseBody.String())
|
||||
}
|
||||
inconsistentMetadata := new(hasura.GetInconsistentMetadataResponse)
|
||||
if err := json.NewDecoder(responseBody).Decode(inconsistentMetadata); err != nil {
|
||||
return nil, fmt.Errorf("decoding response: %w", err)
|
||||
}
|
||||
return inconsistentMetadata, nil
|
||||
}
|
||||
|
||||
func (c *ClientCommonMetadataOps) GetInconsistentMetadataReader() (io.Reader, error) {
|
||||
// GetInconsistentMetadataRaw
|
||||
// https://hasura.io/docs/latest/graphql/core/api-reference/metadata-api/manage-metadata.html#metadata-get-inconsistent-metadata
|
||||
func (c *ClientCommonMetadataOps) GetInconsistentMetadataRaw() (io.Reader, error) {
|
||||
request := hasura.RequestBody{
|
||||
Type: "get_inconsistent_metadata",
|
||||
Args: map[string]string{},
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"github.com/hasura/graphql-engine/cli/v2/internal/httpc"
|
||||
)
|
||||
|
||||
// general hasura metadata API requests
|
||||
// these are not dependent on the connected source type
|
||||
// CommonMetadataOperations represents Metadata API's which are not source type specific
|
||||
type CommonMetadataOperations interface {
|
||||
ExportMetadata() (metadata io.Reader, err error)
|
||||
ClearMetadata() (io.Reader, error)
|
||||
@ -15,7 +14,7 @@ type CommonMetadataOperations interface {
|
||||
DropInconsistentMetadata() (io.Reader, error)
|
||||
ReplaceMetadata(metadata io.Reader) (io.Reader, error)
|
||||
GetInconsistentMetadata() (*GetInconsistentMetadataResponse, error)
|
||||
GetInconsistentMetadataReader() (io.Reader, error)
|
||||
GetInconsistentMetadataRaw() (io.Reader, error)
|
||||
SendCommonMetadataOperation(requestBody interface{}) (httpcResponse *httpc.Response, body io.Reader, error error)
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,11 @@ func (p *ProjectMetadata) Reload() (io.Reader, error) {
|
||||
return metadataHandler.ReloadMetadata()
|
||||
}
|
||||
|
||||
// GetInconsistentMetadata objects from hge server
|
||||
func (p *ProjectMetadata) GetInconsistentMetadata() (io.Reader, error) {
|
||||
return cli.GetCommonMetadataOps(p.ec).GetInconsistentMetadataRaw()
|
||||
}
|
||||
|
||||
// Diff will return the differences between metadata in the project (in JSON) and on the server
|
||||
func (p *ProjectMetadata) Diff() (io.Reader, error) {
|
||||
w := new(bytes.Buffer)
|
||||
|
@ -1,10 +1,18 @@
|
||||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hasura/graphql-engine/cli/v2/internal/hasura"
|
||||
|
||||
"github.com/hasura/graphql-engine/cli/v2/pkg/migrate"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/hasura/graphql-engine/cli/v2/internal/testutil"
|
||||
@ -204,3 +212,113 @@ func TestProjectMetadata_Reload(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectMetadata_GetInconsistentMetadata(t *testing.T) {
|
||||
type before func(t *testing.T, p *ProjectMetadata, m *migrate.ProjectMigrate, hgePort, queryEndpoint string)
|
||||
configV2Before := func(t *testing.T, metadata *ProjectMetadata, migrations *migrate.ProjectMigrate, hgePort, queryEndpoint string) {
|
||||
// - apply all migrations
|
||||
// - apply metadata
|
||||
// - drop a table via run_sql API
|
||||
// - reload metadata
|
||||
err := migrations.Apply(migrate.ApplyOnAllDatabases())
|
||||
require.NoError(t, err)
|
||||
_, err = metadata.Apply()
|
||||
require.NoError(t, err)
|
||||
|
||||
// remove a table from database
|
||||
c := testutil.NewHttpcClient(t, hgePort, nil)
|
||||
r, err := c.NewRequest(
|
||||
http.MethodPost,
|
||||
queryEndpoint,
|
||||
hasura.RequestBody{
|
||||
Type: "run_sql",
|
||||
Args: hasura.PGRunSQLInput{
|
||||
SQL: "DROP table t1;",
|
||||
CheckMetadataConsistency: func() *bool { var v = false; return &v }(),
|
||||
},
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
resp, err := c.Do(context.Background(), r, nil)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = metadata.Reload()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
type fields struct {
|
||||
projectDirectory string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
before before
|
||||
hasuraImage string
|
||||
queryEndpoint string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"can list inconsistent metadata config v3",
|
||||
fields{
|
||||
projectDirectory: "testdata/projectv3",
|
||||
},
|
||||
func(t *testing.T, metadata *ProjectMetadata, _ *migrate.ProjectMigrate, _ string, _ string) {
|
||||
_, err := metadata.Apply()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
testutil.HasuraDockerImage,
|
||||
"v2/query",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"can list inconsistent metadata config v2",
|
||||
fields{
|
||||
projectDirectory: "testdata/projectv2",
|
||||
},
|
||||
configV2Before,
|
||||
testutil.HasuraDockerImage,
|
||||
"v2/query",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"can list inconsistent metadata config v2 v1.3.3",
|
||||
fields{
|
||||
projectDirectory: "testdata/projectv2",
|
||||
},
|
||||
configV2Before,
|
||||
"hasura/graphql-engine:v1.3.3",
|
||||
"v1/query",
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
port, teardown := testutil.StartHasura(t, tt.hasuraImage)
|
||||
hgeEndpoint := fmt.Sprintf("%s:%s", testutil.BaseURL, port)
|
||||
defer teardown()
|
||||
|
||||
migrations, err := migrate.NewProjectMigrate(tt.fields.projectDirectory, migrate.WithEndpoint(hgeEndpoint), migrate.WithAdminSecret(testutil.TestAdminSecret))
|
||||
require.NoError(t, err)
|
||||
metadata, err := NewProjectMetadata(tt.fields.projectDirectory, WithEndpoint(hgeEndpoint), WithAdminSecret(testutil.TestAdminSecret))
|
||||
require.NoError(t, err)
|
||||
if tt.before != nil {
|
||||
tt.before(t, metadata, migrations, port, tt.queryEndpoint)
|
||||
}
|
||||
got, err := metadata.GetInconsistentMetadata()
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
gotb, err := ioutil.ReadAll(got)
|
||||
require.NoError(t, err)
|
||||
goldenFile := filepath.Join("testdata/get_inconsistent_metadata_test", strings.Join(strings.Split(tt.name, " "), "_")+".golden.json")
|
||||
|
||||
// uncomment the following line to update test golden file
|
||||
// require.NoError(t, ioutil.WriteFile(goldenFile, gotb, 0655))
|
||||
|
||||
wantb, err := ioutil.ReadFile(goldenFile)
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, string(wantb), string(gotb))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"is_consistent": false,
|
||||
"inconsistent_objects": [
|
||||
{
|
||||
"definition": {
|
||||
"schema": "public",
|
||||
"name": "t1"
|
||||
},
|
||||
"reason": "Inconsistent object: no such table/view exists in source: \"t1\"",
|
||||
"name": "table t1 in source default",
|
||||
"type": "table"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"is_consistent": false,
|
||||
"inconsistent_objects": [
|
||||
{
|
||||
"definition": {
|
||||
"schema": "public",
|
||||
"name": "t1"
|
||||
},
|
||||
"reason": "no such table/view exists in postgres: \"t1\"",
|
||||
"type": "table"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"is_consistent": false,
|
||||
"inconsistent_objects": [
|
||||
{
|
||||
"definition": {
|
||||
"schema": "public",
|
||||
"name": "t1"
|
||||
},
|
||||
"reason": "Inconsistent object: no such table/view exists in source: \"t1\"",
|
||||
"name": "table t1 in source default",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"schema": "public",
|
||||
"name": "t2"
|
||||
},
|
||||
"reason": "Inconsistent object: no such table/view exists in source: \"t2\"",
|
||||
"name": "table t2 in source default",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"schema": "pub",
|
||||
"name": "t4"
|
||||
},
|
||||
"reason": "Inconsistent object: no such table/view exists in source: \"pub.t4\"",
|
||||
"name": "table pub.t4 in source default",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"definition": {
|
||||
"schema": "pub",
|
||||
"name": "t3"
|
||||
},
|
||||
"reason": "Inconsistent object: no such table/view exists in source: \"pub.t3\"",
|
||||
"name": "table pub.t3 in source default",
|
||||
"type": "table"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user