@@ -3,6 +3,7 @@ package agentcontainers_test
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+ "errors"
6
7
"fmt"
7
8
"math/rand"
8
9
"net/http"
@@ -1649,6 +1650,111 @@ func TestAPI(t *testing.T) {
1649
1650
assert .Empty (t , fakeSAC .agents )
1650
1651
})
1651
1652
1653
+ t .Run ("Error" , func (t * testing.T ) {
1654
+ t .Parallel ()
1655
+
1656
+ var (
1657
+ ctx = testutil .Context (t , testutil .WaitMedium )
1658
+ logger = slogtest .Make (t , & slogtest.Options {IgnoreErrors : true }).Leveled (slog .LevelDebug )
1659
+ mClock = quartz .NewMock (t )
1660
+ mCCLI = acmock .NewMockContainerCLI (gomock .NewController (t ))
1661
+ fDCCLI = & fakeDevcontainerCLI {}
1662
+ fSAC = & fakeSubAgentClient {
1663
+ logger : logger .Named ("fakeSubAgentClient" ),
1664
+ createErrC : make (chan error , 1 ),
1665
+ }
1666
+
1667
+ testContainer = codersdk.WorkspaceAgentContainer {
1668
+ ID : "test-container-id" ,
1669
+ FriendlyName : "test-container" ,
1670
+ Image : "test-image" ,
1671
+ Running : true ,
1672
+ CreatedAt : time .Now (),
1673
+ Labels : map [string ]string {
1674
+ agentcontainers .DevcontainerLocalFolderLabel : "/workspaces" ,
1675
+ agentcontainers .DevcontainerConfigFileLabel : "/workspace/.devcontainer/devcontainer.json" ,
1676
+ },
1677
+ }
1678
+ )
1679
+
1680
+ coderBin , err := os .Executable ()
1681
+ require .NoError (t , err )
1682
+
1683
+ // Mock the `List` function to always return the test container.
1684
+ mCCLI .EXPECT ().List (gomock .Any ()).Return (codersdk.WorkspaceAgentListContainersResponse {
1685
+ Containers : []codersdk.WorkspaceAgentContainer {testContainer },
1686
+ }, nil ).AnyTimes ()
1687
+
1688
+ // We're going to force the container CLI to fail, which will allow us to test the
1689
+ // error handling.
1690
+ var simulatedError = errors .New ("simulated error" )
1691
+ mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), testContainer .ID ).Return ("" , simulatedError ).Times (1 )
1692
+
1693
+ mClock .Set (time .Now ()).MustWait (ctx )
1694
+ tickerTrap := mClock .Trap ().TickerFunc ("updaterLoop" )
1695
+
1696
+ api := agentcontainers .NewAPI (logger ,
1697
+ agentcontainers .WithClock (mClock ),
1698
+ agentcontainers .WithContainerCLI (mCCLI ),
1699
+ agentcontainers .WithDevcontainerCLI (fDCCLI ),
1700
+ agentcontainers .WithSubAgentClient (fSAC ),
1701
+ agentcontainers .WithSubAgentURL ("test-subagent-url" ),
1702
+ agentcontainers .WithWatcher (watcher .NewNoop ()),
1703
+ )
1704
+ api .Start ()
1705
+ defer func () {
1706
+ close (fSAC .createErrC )
1707
+ api .Close ()
1708
+ }()
1709
+
1710
+ r := chi .NewRouter ()
1711
+ r .Mount ("/" , api .Routes ())
1712
+
1713
+ // Given: We allow an attempt at creation to occur.
1714
+ tickerTrap .MustWait (ctx ).MustRelease (ctx )
1715
+ tickerTrap .Close ()
1716
+
1717
+ req := httptest .NewRequest (http .MethodGet , "/" , nil )
1718
+ rec := httptest .NewRecorder ()
1719
+ r .ServeHTTP (rec , req )
1720
+ require .Equal (t , http .StatusOK , rec .Code )
1721
+
1722
+ var response codersdk.WorkspaceAgentListContainersResponse
1723
+ err = json .NewDecoder (rec .Body ).Decode (& response )
1724
+ require .NoError (t , err )
1725
+
1726
+ // Then: We expect that there will be an error associated with the devcontainer.
1727
+ require .Len (t , response .Devcontainers , 1 )
1728
+ require .Equal (t , "detect architecture: simulated error" , response .Devcontainers [0 ].Error )
1729
+
1730
+ gomock .InOrder (
1731
+ mCCLI .EXPECT ().DetectArchitecture (gomock .Any (), testContainer .ID ).Return (runtime .GOARCH , nil ),
1732
+ mCCLI .EXPECT ().ExecAs (gomock .Any (), testContainer .ID , "root" , "mkdir" , "-p" , "/.coder-agent" ).Return (nil , nil ),
1733
+ mCCLI .EXPECT ().Copy (gomock .Any (), testContainer .ID , coderBin , "/.coder-agent/coder" ).Return (nil ),
1734
+ mCCLI .EXPECT ().ExecAs (gomock .Any (), testContainer .ID , "root" , "chmod" , "0755" , "/.coder-agent" , "/.coder-agent/coder" ).Return (nil , nil ),
1735
+ mCCLI .EXPECT ().ExecAs (gomock .Any (), testContainer .ID , "root" , "/bin/sh" , "-c" , "chown $(id -u):$(id -g) /.coder-agent/coder" ).Return (nil , nil ),
1736
+ )
1737
+
1738
+ // Given: We allow creation to succeed.
1739
+ testutil .RequireSend (ctx , t , fSAC .createErrC , nil )
1740
+
1741
+ _ , aw := mClock .AdvanceNext ()
1742
+ aw .MustWait (ctx )
1743
+
1744
+ req = httptest .NewRequest (http .MethodGet , "/" , nil )
1745
+ rec = httptest .NewRecorder ()
1746
+ r .ServeHTTP (rec , req )
1747
+ require .Equal (t , http .StatusOK , rec .Code )
1748
+
1749
+ response = codersdk.WorkspaceAgentListContainersResponse {}
1750
+ err = json .NewDecoder (rec .Body ).Decode (& response )
1751
+ require .NoError (t , err )
1752
+
1753
+ // Then: We expect that the error will be gone
1754
+ require .Len (t , response .Devcontainers , 1 )
1755
+ require .Equal (t , "" , response .Devcontainers [0 ].Error )
1756
+ })
1757
+
1652
1758
t .Run ("Create" , func (t * testing.T ) {
1653
1759
t .Parallel ()
1654
1760
0 commit comments