Skip to content

Commit 520a1ca

Browse files
committed
Add tests
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent 24b37d9 commit 520a1ca

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

coderd/database/dbmem/dbmem.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7680,6 +7680,7 @@ func (q *FakeQuerier) InsertTemplate(_ context.Context, arg database.InsertTempl
76807680
AllowUserAutostart: true,
76817681
AllowUserAutostop: true,
76827682
MaxPortSharingLevel: arg.MaxPortSharingLevel,
7683+
CORSBehavior: arg.CORSBehavior,
76837684
}
76847685
q.templates = append(q.templates, template)
76857686
return nil
@@ -9213,6 +9214,7 @@ func (q *FakeQuerier) UpdateTemplateMetaByID(_ context.Context, arg database.Upd
92139214
tpl.GroupACL = arg.GroupACL
92149215
tpl.AllowUserCancelWorkspaceJobs = arg.AllowUserCancelWorkspaceJobs
92159216
tpl.MaxPortSharingLevel = arg.MaxPortSharingLevel
9217+
tpl.CORSBehavior = arg.CORSBehavior
92169218
q.templates[idx] = tpl
92179219
return nil
92189220
}

coderd/workspaceapps/apptest/apptest.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,151 @@ func Run(t *testing.T, appHostIsPrimary bool, factory DeploymentFactory) {
14631463
require.Equal(t, http.StatusOK, resp.StatusCode)
14641464
assertWorkspaceLastUsedAtUpdated(t, appDetails)
14651465
})
1466+
1467+
t.Run("CORS", func(t *testing.T) {
1468+
t.Parallel()
1469+
1470+
// Set up test headers that should be returned by the app
1471+
testHeaders := http.Header{
1472+
"Access-Control-Allow-Origin": []string{"*"},
1473+
"Access-Control-Allow-Methods": []string{"GET, POST, OPTIONS"},
1474+
}
1475+
1476+
unauthenticatedClient := func(t *testing.T, appDetails *Details) *codersdk.Client {
1477+
c := appDetails.AppClient(t)
1478+
c.SetSessionToken("")
1479+
return c
1480+
}
1481+
1482+
authenticatedClient := func(t *testing.T, appDetails *Details) *codersdk.Client {
1483+
uc, _ := coderdtest.CreateAnotherUser(t, appDetails.SDKClient, appDetails.FirstUser.OrganizationID, rbac.RoleMember())
1484+
c := appDetails.AppClient(t)
1485+
c.SetSessionToken(uc.SessionToken())
1486+
return c
1487+
}
1488+
1489+
ownerClient := func(t *testing.T, appDetails *Details) *codersdk.Client {
1490+
return appDetails.SDKClient
1491+
}
1492+
1493+
tests := []struct {
1494+
name string
1495+
shareLevel codersdk.WorkspaceAgentPortShareLevel
1496+
behavior codersdk.AppCORSBehavior
1497+
client func(t *testing.T, appDetails *Details) *codersdk.Client
1498+
expectedStatusCode int
1499+
expectedCORSHeaders bool
1500+
}{
1501+
// Public
1502+
{
1503+
name: "Default/Public",
1504+
shareLevel: codersdk.WorkspaceAgentPortShareLevelPublic,
1505+
behavior: codersdk.AppCORSBehaviorSimple,
1506+
expectedCORSHeaders: false,
1507+
client: unauthenticatedClient,
1508+
expectedStatusCode: http.StatusOK,
1509+
},
1510+
{
1511+
name: "Passthru/Public",
1512+
shareLevel: codersdk.WorkspaceAgentPortShareLevelPublic,
1513+
behavior: codersdk.AppCORSBehaviorPassthru,
1514+
expectedCORSHeaders: true,
1515+
client: unauthenticatedClient,
1516+
expectedStatusCode: http.StatusOK,
1517+
},
1518+
// Authenticated
1519+
{
1520+
name: "Default/Authenticated",
1521+
shareLevel: codersdk.WorkspaceAgentPortShareLevelAuthenticated,
1522+
behavior: codersdk.AppCORSBehaviorSimple,
1523+
expectedCORSHeaders: false,
1524+
client: authenticatedClient,
1525+
expectedStatusCode: http.StatusOK,
1526+
},
1527+
{
1528+
name: "Passthru/Authenticated",
1529+
shareLevel: codersdk.WorkspaceAgentPortShareLevelAuthenticated,
1530+
behavior: codersdk.AppCORSBehaviorPassthru,
1531+
expectedCORSHeaders: true,
1532+
client: authenticatedClient,
1533+
expectedStatusCode: http.StatusOK,
1534+
},
1535+
{
1536+
// The CORS behavior will not affect unauthenticated requests.
1537+
// The request will be redirected to the login page.
1538+
name: "Passthru/Unauthenticated",
1539+
shareLevel: codersdk.WorkspaceAgentPortShareLevelAuthenticated,
1540+
behavior: codersdk.AppCORSBehaviorPassthru,
1541+
expectedCORSHeaders: false,
1542+
client: unauthenticatedClient,
1543+
expectedStatusCode: http.StatusSeeOther,
1544+
},
1545+
// Owner
1546+
{
1547+
name: "Default/Owner",
1548+
shareLevel: codersdk.WorkspaceAgentPortShareLevelAuthenticated, // Owner is not a valid share level for ports.
1549+
behavior: codersdk.AppCORSBehaviorSimple,
1550+
expectedCORSHeaders: false,
1551+
client: ownerClient,
1552+
expectedStatusCode: http.StatusOK,
1553+
},
1554+
{
1555+
name: "Passthru/Owner",
1556+
shareLevel: codersdk.WorkspaceAgentPortShareLevelAuthenticated, // Owner is not a valid share level for ports.
1557+
behavior: codersdk.AppCORSBehaviorPassthru,
1558+
expectedCORSHeaders: true,
1559+
client: ownerClient,
1560+
expectedStatusCode: http.StatusOK,
1561+
},
1562+
}
1563+
1564+
for _, tc := range tests {
1565+
t.Run(tc.name, func(t *testing.T) {
1566+
t.Parallel()
1567+
1568+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
1569+
defer cancel()
1570+
1571+
appDetails := setupProxyTest(t, &DeploymentOptions{
1572+
headers: testHeaders,
1573+
})
1574+
port, err := strconv.ParseInt(appDetails.Apps.Port.AppSlugOrPort, 10, 32)
1575+
require.NoError(t, err)
1576+
1577+
// Update the template CORS behavior.
1578+
b := codersdk.AppCORSBehavior(tc.behavior)
1579+
template, err := appDetails.SDKClient.UpdateTemplateMeta(ctx, appDetails.Workspace.TemplateID, codersdk.UpdateTemplateMeta{
1580+
CORSBehavior: &b,
1581+
})
1582+
require.NoError(t, err)
1583+
require.Equal(t, tc.behavior, template.CORSBehavior)
1584+
1585+
// Set the port we have to be shared.
1586+
_, err = appDetails.SDKClient.UpsertWorkspaceAgentPortShare(ctx, appDetails.Workspace.ID, codersdk.UpsertWorkspaceAgentPortShareRequest{
1587+
AgentName: proxyTestAgentName,
1588+
Port: int32(port),
1589+
ShareLevel: tc.shareLevel,
1590+
Protocol: codersdk.WorkspaceAgentPortShareProtocolHTTP,
1591+
})
1592+
require.NoError(t, err)
1593+
1594+
client := tc.client(t, appDetails)
1595+
1596+
resp, err := requestWithRetries(ctx, t, client, http.MethodGet, appDetails.SubdomainAppURL(appDetails.Apps.Port).String(), nil)
1597+
require.NoError(t, err)
1598+
defer resp.Body.Close()
1599+
require.Equal(t, tc.expectedStatusCode, resp.StatusCode)
1600+
1601+
if tc.expectedCORSHeaders {
1602+
require.Equal(t, testHeaders.Get("Access-Control-Allow-Origin"), resp.Header.Get("Access-Control-Allow-Origin"))
1603+
require.Equal(t, testHeaders.Get("Access-Control-Allow-Methods"), resp.Header.Get("Access-Control-Allow-Methods"))
1604+
} else {
1605+
require.Empty(t, resp.Header.Get("Access-Control-Allow-Origin"))
1606+
require.Empty(t, resp.Header.Get("Access-Control-Allow-Methods"))
1607+
}
1608+
})
1609+
}
1610+
})
14661611
})
14671612

14681613
t.Run("AppSharing", func(t *testing.T) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy