1+ // Package dolthubdouble provides an in-process HTTP double for the DoltHub
2+ // API, used by the e2e test harness to exercise remote-facing code paths
3+ // without depending on dolthub.com.
14package dolthubdouble
25
36import (
@@ -20,6 +23,7 @@ import (
2023
2124const schemaCommitMessage = "Initialize wl-commons schema v1.0"
2225
26+ // RequestLog captures a single HTTP request observed by the double.
2327type RequestLog struct {
2428 Method string `json:"method"`
2529 Path string `json:"path"`
@@ -28,17 +32,22 @@ type RequestLog struct {
2832 Body string `json:"body,omitempty"`
2933}
3034
35+ // RepoRef identifies a DoltHub repository by owner/db.
3136type RepoRef struct {
3237 Owner string `json:"owner"`
3338 DB string `json:"db"`
3439}
3540
41+ // BranchSeed describes a branch to create during Seed, optionally forked
42+ // from an existing branch and populated with SQL statements.
3643type BranchSeed struct {
3744 Name string `json:"name"`
3845 From string `json:"from,omitempty"`
3946 SQL []string `json:"sql,omitempty"`
4047}
4148
49+ // RepositorySeed describes a repository to create during Seed, including
50+ // any fork relationship, initial main-branch SQL, and additional branches.
4251type RepositorySeed struct {
4352 Owner string `json:"owner"`
4453 DB string `json:"db"`
@@ -47,6 +56,7 @@ type RepositorySeed struct {
4756 Branches []BranchSeed `json:"branches,omitempty"`
4857}
4958
59+ // PRSeed describes a pull request to create during Seed.
5060type PRSeed struct {
5161 ID string `json:"id,omitempty"`
5262 UpstreamOwner string `json:"upstream_owner"`
@@ -60,25 +70,32 @@ type PRSeed struct {
6070 Description string `json:"description,omitempty"`
6171}
6272
73+ // SeedRequest is the JSON body accepted by the double's seed endpoint.
6374type SeedRequest struct {
6475 Repositories []RepositorySeed `json:"repositories,omitempty"`
6576 PRs []PRSeed `json:"prs,omitempty"`
6677}
6778
79+ // RepositorySnapshot captures a point-in-time view of a repository's
80+ // branches and pull requests.
6881type RepositorySnapshot struct {
6982 Owner string `json:"owner"`
7083 DB string `json:"db"`
7184 Branches map [string ]BranchSnapshot `json:"branches"`
7285 PullRequest []PullRequestSnapshot `json:"pull_requests,omitempty"`
7386}
7487
88+ // BranchSnapshot captures the row contents of each well-known table on
89+ // a single branch.
7590type BranchSnapshot struct {
7691 Wanted []map [string ]string `json:"wanted,omitempty"`
7792 Completions []map [string ]string `json:"completions,omitempty"`
7893 Stamps []map [string ]string `json:"stamps,omitempty"`
7994 Rigs []map [string ]string `json:"rigs,omitempty"`
8095}
8196
97+ // PullRequestSnapshot captures a single pull request's state for test
98+ // assertions.
8299type PullRequestSnapshot struct {
83100 ID string `json:"id"`
84101 UpstreamOwner string `json:"upstream_owner"`
@@ -93,12 +110,15 @@ type PullRequestSnapshot struct {
93110 URL string `json:"url"`
94111}
95112
113+ // Snapshot is the aggregate of observed requests, repository state, and
114+ // pull request state returned by the double's snapshot endpoint.
96115type Snapshot struct {
97116 Requests []RequestLog `json:"requests"`
98117 Repositories []RepositorySnapshot `json:"repositories"`
99118 PullRequests []PullRequestSnapshot `json:"pull_requests"`
100119}
101120
121+ // Server is an in-process HTTP double for DoltHub's REST and SQL APIs.
102122type Server struct {
103123 root string
104124
@@ -129,6 +149,8 @@ type pullRequest struct {
129149 Description string
130150}
131151
152+ // New returns a Server that stores repository state under root. If root
153+ // is empty, a temporary directory is allocated.
132154func New (root string ) (* Server , error ) {
133155 if root == "" {
134156 tmp , err := os .MkdirTemp ("" , "wasteland-dolthub-double-*" )
@@ -148,10 +170,14 @@ func New(root string) (*Server, error) {
148170 }, nil
149171}
150172
173+ // Close removes the server's root directory and any repository state
174+ // underneath it.
151175func (s * Server ) Close () error {
152176 return os .RemoveAll (s .root )
153177}
154178
179+ // Reset removes all repositories, pull requests, and request logs from
180+ // the server while leaving the root directory in place.
155181func (s * Server ) Reset () error {
156182 s .mu .Lock ()
157183 defer s .mu .Unlock ()
@@ -168,6 +194,8 @@ func (s *Server) Reset() error {
168194 return nil
169195}
170196
197+ // Seed applies a SeedRequest: creating repositories, branches, and pull
198+ // requests as described.
171199func (s * Server ) Seed (req SeedRequest ) error {
172200 for _ , repoSeed := range req .Repositories {
173201 if _ , err := s .ensureRepository (repoSeed ); err != nil {
@@ -182,6 +210,8 @@ func (s *Server) Seed(req SeedRequest) error {
182210 return nil
183211}
184212
213+ // Snapshot returns a point-in-time view of observed requests, repository
214+ // contents, and pull-request state. baseURL is used to compose PR URLs.
185215func (s * Server ) Snapshot (baseURL string ) (Snapshot , error ) {
186216 s .mu .Lock ()
187217 requests := append ([]RequestLog (nil ), s .requests ... )
@@ -226,6 +256,9 @@ func (s *Server) Snapshot(baseURL string) (Snapshot, error) {
226256 }, nil
227257}
228258
259+ // MergePR merges the specified PR by copying changed rows from the source
260+ // branch into the upstream repo's main branch, mirroring DoltHub's
261+ // server-side merge behavior for the double's test contract.
229262func (s * Server ) MergePR (prID string ) error {
230263 s .mu .Lock ()
231264 pr , ok := s .prs [prID ]
@@ -279,6 +312,8 @@ func (s *Server) MergePR(prID string) error {
279312 return nil
280313}
281314
315+ // Handler returns an http.Handler serving the double's emulated
316+ // DoltHub REST and SQL endpoints.
282317func (s * Server ) Handler () http.Handler {
283318 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
284319 s .recordRequest (r )
@@ -329,10 +364,10 @@ func (s *Server) handleAPI(w http.ResponseWriter, r *http.Request) {
329364 owner := parts [0 ]
330365 db := parts [1 ]
331366
332- switch {
333- case parts [ 2 ] == "pulls" :
367+ switch parts [ 2 ] {
368+ case "pulls" :
334369 s .handlePulls (w , r , owner , db , parts [3 :])
335- case parts [ 2 ] == "write" :
370+ case "write" :
336371 s .handleWrite (w , r , owner , db , parts [3 :])
337372 default :
338373 s .handleQuery (w , r , owner , db , strings .Join (parts [2 :], "/" ))
@@ -343,7 +378,7 @@ func (s *Server) handlePulls(w http.ResponseWriter, r *http.Request, owner, db s
343378 switch {
344379 case len (rest ) == 0 && r .Method == http .MethodGet :
345380 pulls := s .listPRs (owner , db )
346- writeJSON (w , http . StatusOK , map [string ]any {"pulls" : pulls })
381+ writeJSON (w , map [string ]any {"pulls" : pulls })
347382 case len (rest ) == 0 && r .Method == http .MethodPost :
348383 var req struct {
349384 Title string `json:"title"`
@@ -374,14 +409,14 @@ func (s *Server) handlePulls(w http.ResponseWriter, r *http.Request, owner, db s
374409 http .Error (w , err .Error (), http .StatusBadRequest )
375410 return
376411 }
377- writeJSON (w , http . StatusOK , map [string ]any {"_id" : pr .ID , "status" : pr .State })
412+ writeJSON (w , map [string ]any {"_id" : pr .ID , "status" : pr .State })
378413 case len (rest ) == 1 && r .Method == http .MethodGet :
379414 pr , ok := s .getPR (rest [0 ])
380415 if ! ok || pr .UpstreamOwner != owner || pr .UpstreamDB != db {
381416 http .NotFound (w , r )
382417 return
383418 }
384- writeJSON (w , http . StatusOK , map [string ]any {
419+ writeJSON (w , map [string ]any {
385420 "from_branch" : pr .FromBranch ,
386421 "from_branch_owner" : pr .FromBranchOwner ,
387422 "author" : pr .Author ,
@@ -396,15 +431,15 @@ func (s *Server) handlePulls(w http.ResponseWriter, r *http.Request, owner, db s
396431 http .Error (w , err .Error (), http .StatusBadRequest )
397432 return
398433 }
399- writeJSON (w , http . StatusOK , map [string ]string {"status" : "ok" })
434+ writeJSON (w , map [string ]string {"status" : "ok" })
400435 default :
401436 http .NotFound (w , r )
402437 }
403438}
404439
405440func (s * Server ) handleWrite (w http.ResponseWriter , r * http.Request , owner , db string , rest []string ) {
406441 if len (rest ) == 0 && r .Method == http .MethodGet {
407- writeJSON (w , http . StatusOK , map [string ]any {
442+ writeJSON (w , map [string ]any {
408443 "done" : true ,
409444 "res_details" : map [string ]string {
410445 "query_execution_status" : "Success" ,
@@ -434,7 +469,7 @@ func (s *Server) handleWrite(w http.ResponseWriter, r *http.Request, owner, db s
434469 return
435470 }
436471
437- writeJSON (w , http . StatusOK , map [string ]any {
472+ writeJSON (w , map [string ]any {
438473 "query_execution_status" : "Success" ,
439474 "query_execution_message" : "" ,
440475 })
@@ -453,7 +488,7 @@ func (s *Server) handleQuery(w http.ResponseWriter, r *http.Request, owner, db,
453488 http .Error (w , err .Error (), http .StatusNotFound )
454489 return
455490 }
456- writeJSON (w , http . StatusOK , map [string ]any {
491+ writeJSON (w , map [string ]any {
457492 "query_execution_status" : "Success" ,
458493 "repository_owner" : owner ,
459494 "repository_name" : db ,
@@ -473,7 +508,7 @@ func (s *Server) handleQuery(w http.ResponseWriter, r *http.Request, owner, db,
473508 http .Error (w , err .Error (), http .StatusInternalServerError )
474509 return
475510 }
476- writeJSON (w , http . StatusOK , response )
511+ writeJSON (w , response )
477512}
478513
479514func (s * Server ) recordRequest (r * http.Request ) {
@@ -908,9 +943,7 @@ func csvToQueryResponse(owner, db, ref, sqlQuery, csvData string) (map[string]an
908943 })
909944 }
910945 rowObjects := make ([]map [string ]string , 0 , len (rows ))
911- for _ , row := range rows {
912- rowObjects = append (rowObjects , row )
913- }
946+ rowObjects = append (rowObjects , rows ... )
914947 return map [string ]any {
915948 "query_execution_status" : "Success" ,
916949 "query_execution_message" : "" ,
@@ -953,9 +986,9 @@ func parseCSV(csvData string) ([]string, []map[string]string, error) {
953986 return headers , rows , nil
954987}
955988
956- func writeJSON (w http.ResponseWriter , status int , value any ) {
989+ func writeJSON (w http.ResponseWriter , value any ) {
957990 w .Header ().Set ("Content-Type" , "application/json" )
958- w .WriteHeader (status )
991+ w .WriteHeader (http . StatusOK )
959992 _ = json .NewEncoder (w ).Encode (value )
960993}
961994
@@ -1147,10 +1180,3 @@ func copyDir(src, dest string) error {
11471180 return os .WriteFile (target , data , info .Mode ())
11481181 })
11491182}
1150-
1151- func max (a , b int ) int {
1152- if a > b {
1153- return a
1154- }
1155- return b
1156- }
0 commit comments