github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/intents/intents_test.go (about)

     1  package intents
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/cozy/cozy-stack/model/app"
     7  	"github.com/cozy/cozy-stack/model/instance/lifecycle"
     8  	"github.com/cozy/cozy-stack/model/permission"
     9  	"github.com/cozy/cozy-stack/pkg/config/config"
    10  	"github.com/cozy/cozy-stack/pkg/consts"
    11  	"github.com/cozy/cozy-stack/pkg/couchdb"
    12  	"github.com/cozy/cozy-stack/tests/testutils"
    13  	"github.com/cozy/cozy-stack/web/errors"
    14  	"github.com/gavv/httpexpect/v2"
    15  	"github.com/labstack/echo/v4"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestIntents(t *testing.T) {
    20  	if testing.Short() {
    21  		t.Skip("an instance is required for this test: test skipped due to the use of --short flag")
    22  	}
    23  
    24  	var err error
    25  	var intentID string
    26  
    27  	config.UseTestFile(t)
    28  	testutils.NeedCouchdb(t)
    29  	setup := testutils.NewSetup(t, t.Name())
    30  	ins := setup.GetTestInstance(&lifecycle.Options{
    31  		Domain: "cozy.example.net",
    32  	})
    33  	_, _ = setup.GetTestClient(consts.Settings)
    34  
    35  	webapp := &couchdb.JSONDoc{
    36  		Type: consts.Apps,
    37  		M: map[string]interface{}{
    38  			"_id":  consts.Apps + "/app",
    39  			"slug": "app",
    40  		},
    41  	}
    42  	require.NoError(t, couchdb.CreateNamedDoc(ins, webapp))
    43  
    44  	appPerms, err := permission.CreateWebappSet(ins, "app", permission.Set{}, "1.0.0")
    45  	if err != nil {
    46  		require.NoError(t, err)
    47  	}
    48  	appToken := ins.BuildAppToken("app", "")
    49  	files := &couchdb.JSONDoc{
    50  		Type: consts.Apps,
    51  		M: map[string]interface{}{
    52  			"_id":  consts.Apps + "/files",
    53  			"slug": "files",
    54  			"intents": []app.Intent{
    55  				{
    56  					Action: "PICK",
    57  					Types:  []string{"io.cozy.files", "image/gif"},
    58  					Href:   "/pick",
    59  				},
    60  			},
    61  		},
    62  	}
    63  
    64  	require.NoError(t, couchdb.CreateNamedDoc(ins, files))
    65  	if _, err := permission.CreateWebappSet(ins, "files", permission.Set{}, "1.0.0"); err != nil {
    66  		require.NoError(t, err)
    67  	}
    68  	filesToken := ins.BuildAppToken("files", "")
    69  
    70  	ts := setup.GetTestServer("/intents", Routes)
    71  	ts.Config.Handler.(*echo.Echo).HTTPErrorHandler = errors.ErrorHandler
    72  	t.Cleanup(ts.Close)
    73  
    74  	t.Run("CreateIntent", func(t *testing.T) {
    75  		e := testutils.CreateTestClient(t, ts.URL)
    76  
    77  		obj := e.POST("/intents").
    78  			WithHeader("Authorization", "Bearer "+appToken).
    79  			WithHeader("Content-Type", "application/vnd.api+json").
    80  			WithHeader("Accept", "application/vnd.api+json").
    81  			WithBytes([]byte(`{
    82          "data": {
    83            "type": "io.cozy.settings",
    84            "attributes": {
    85              "action": "PICK",
    86              "type": "io.cozy.files",
    87              "permissions": ["GET"]
    88            }
    89          }
    90        }`)).
    91  			Expect().Status(200).
    92  			JSON(httpexpect.ContentOpts{MediaType: "application/vnd.api+json"}).
    93  			Object()
    94  
    95  		intentID = checkIntentResult(obj, appPerms, true)
    96  	})
    97  
    98  	t.Run("GetIntent", func(t *testing.T) {
    99  		e := testutils.CreateTestClient(t, ts.URL)
   100  
   101  		obj := e.GET("/intents/"+intentID).
   102  			WithHeader("Authorization", "Bearer "+filesToken).
   103  			WithHeader("Accept", "application/vnd.api+json").
   104  			Expect().Status(200).
   105  			JSON(httpexpect.ContentOpts{MediaType: "application/vnd.api+json"}).
   106  			Object()
   107  
   108  		checkIntentResult(obj, appPerms, true)
   109  	})
   110  
   111  	t.Run("GetIntentNotFromTheService", func(t *testing.T) {
   112  		e := testutils.CreateTestClient(t, ts.URL)
   113  
   114  		e.GET("/intents/"+intentID).
   115  			WithHeader("Authorization", "Bearer "+appToken).
   116  			WithHeader("Accept", "application/vnd.api+json").
   117  			Expect().Status(403)
   118  	})
   119  
   120  	t.Run("CreateIntentOAuth", func(t *testing.T) {
   121  		e := testutils.CreateTestClient(t, ts.URL)
   122  
   123  		obj := e.POST("/intents").
   124  			WithHeader("Authorization", "Bearer "+appToken).
   125  			WithHeader("Content-Type", "application/vnd.api+json").
   126  			WithHeader("Accept", "application/vnd.api+json").
   127  			WithBytes([]byte(`{
   128          "data": {
   129            "type": "io.cozy.settings",
   130            "attributes": {
   131              "action": "PICK",
   132              "type": "io.cozy.files",
   133              "permissions": ["GET"]
   134            }
   135          }
   136        }`)).
   137  			Expect().Status(200).
   138  			JSON(httpexpect.ContentOpts{MediaType: "application/vnd.api+json"}).
   139  			Object()
   140  
   141  		checkIntentResult(obj, appPerms, false)
   142  	})
   143  }
   144  
   145  func checkIntentResult(obj *httpexpect.Object, appPerms *permission.Permission, fromWeb bool) string {
   146  	data := obj.Value("data").Object()
   147  	data.ValueEqual("type", "io.cozy.intents")
   148  	intentID := data.Value("id").String().NotEmpty().Raw()
   149  
   150  	attrs := data.Value("attributes").Object()
   151  	attrs.ValueEqual("action", "PICK")
   152  	attrs.ValueEqual("type", "io.cozy.files")
   153  
   154  	perms := attrs.Value("permissions").Array()
   155  	perms.Length().Equal(1)
   156  	perms.First().String().Equal("GET")
   157  
   158  	if !fromWeb {
   159  		return intentID
   160  	}
   161  
   162  	attrs.ValueEqual("client", "https://app.cozy.example.net")
   163  
   164  	links := data.Value("links").Object()
   165  	links.ValueEqual("self", "/intents/"+intentID)
   166  	links.ValueEqual("permissions", "/permissions/"+appPerms.ID())
   167  
   168  	return intentID
   169  }