initDefaultConnection initializes the default postgres connection parameters. It first checks if the database is running at localhost:5432. If it is, it will use that database. If it's not, it will start a new container and use that.
(t TBSubset)
| 58 | // It first checks if the database is running at localhost:5432. If it is, it will |
| 59 | // use that database. If it's not, it will start a new container and use that. |
| 60 | func initDefaultConnection(t TBSubset) error { |
| 61 | params := ConnectionParams{ |
| 62 | Username: "postgres", |
| 63 | Password: "postgres", |
| 64 | Host: "127.0.0.1", |
| 65 | Port: "5432", |
| 66 | DBName: "postgres", |
| 67 | } |
| 68 | dsn := params.DSN() |
| 69 | |
| 70 | // Helper closure to try opening and pinging the default Postgres instance. |
| 71 | // Used within a single retry loop that handles both retryable and permanent errors. |
| 72 | attemptConn := func() error { |
| 73 | db, err := sql.Open("postgres", dsn) |
| 74 | if err == nil { |
| 75 | err = db.Ping() |
| 76 | if closeErr := db.Close(); closeErr != nil { |
| 77 | return xerrors.Errorf("close db: %w", closeErr) |
| 78 | } |
| 79 | } |
| 80 | return err |
| 81 | } |
| 82 | |
| 83 | var dbErr error |
| 84 | // Retry up to 10 seconds for temporary errors. |
| 85 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) |
| 86 | defer cancel() |
| 87 | for r := retry.New(10*time.Millisecond, 500*time.Millisecond); r.Wait(ctx); { |
| 88 | dbErr = attemptConn() |
| 89 | if dbErr == nil { |
| 90 | break |
| 91 | } |
| 92 | errString := dbErr.Error() |
| 93 | if !containsAnySubstring(errString, retryableErrSubstrings) { |
| 94 | break |
| 95 | } |
| 96 | t.Logf("%s failed to connect to postgres, retrying: %s", time.Now().Format(time.StampMilli), errString) |
| 97 | } |
| 98 | |
| 99 | // After the loop dbErr is the last connection error (if any). |
| 100 | if dbErr != nil && containsAnySubstring(dbErr.Error(), noPostgresRunningErrSubstrings) { |
| 101 | // If there's no database running on the default port, we'll start a |
| 102 | // postgres container. We won't be cleaning it up so it can be reused |
| 103 | // by subsequent tests. It'll keep on running until the user terminates |
| 104 | // it manually. |
| 105 | container, _, err := openContainer(t, DBContainerOptions{ |
| 106 | Name: "coder-test-postgres", |
| 107 | Port: 5432, |
| 108 | }) |
| 109 | if err != nil { |
| 110 | return xerrors.Errorf("open container: %w", err) |
| 111 | } |
| 112 | params.Host = container.Host |
| 113 | params.Port = container.Port |
| 114 | dsn = params.DSN() |
| 115 | |
| 116 | // Retry connecting for at most 10 seconds. |
| 117 | // The fact that openContainer succeeded does not |
no test coverage detected