github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/roachtest/sqlalchemy.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package main 12 13 import ( 14 "bufio" 15 "bytes" 16 "context" 17 "fmt" 18 "regexp" 19 "strings" 20 ) 21 22 var sqlAlchemyResultRegex = regexp.MustCompile(`^(?P<test>test.*::.*::[^ \[\]]*(?:\[.*])?) (?P<result>.*)$`) 23 var sqlAlchemyReleaseTagRegex = regexp.MustCompile(`^rel_(?P<major>\d+)_(?P<minor>\d+)_(?P<point>\d+)$`) 24 25 // This test runs the SQLAlchemy dialect test suite against a single Cockroach 26 // node. 27 28 func registerSQLAlchemy(r *testRegistry) { 29 runSQLAlchemy := func( 30 ctx context.Context, 31 t *test, 32 c *cluster, 33 ) { 34 if c.isLocal() { 35 t.Fatal("cannot be run in local mode") 36 } 37 node := c.Node(1) 38 t.Status("setting up cockroach") 39 c.Put(ctx, cockroach, "./cockroach", c.All()) 40 c.Start(ctx, t, c.All()) 41 42 version, err := fetchCockroachVersion(ctx, c, node[0]) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 if err := alterZoneConfigAndClusterSettings(ctx, version, c, node[0]); err != nil { 48 t.Fatal(err) 49 } 50 51 t.Status("cloning sqlalchemy and installing prerequisites") 52 latestTag, err := repeatGetLatestTag(ctx, c, "sqlalchemy", "sqlalchemy", sqlAlchemyReleaseTagRegex) 53 if err != nil { 54 t.Fatal(err) 55 } 56 c.l.Printf("Latest sqlalchemy release is %s.", latestTag) 57 58 // TODO: using the latest version requires the dialect to implement `get_isolation_levels` 59 latestTag = "rel_1_3_14" 60 61 if err := repeatRunE( 62 ctx, c, node, "update apt-get", 63 ` 64 sudo add-apt-repository ppa:deadsnakes/ppa && 65 sudo apt-get -qq update`, 66 ); err != nil { 67 t.Fatal(err) 68 } 69 70 if err := repeatRunE( 71 ctx, 72 c, 73 node, 74 "install dependencies", 75 `sudo apt-get -qq install make python3.7 libpq-dev python3.7-dev gcc python3-setuptools python-setuptools build-essential`, 76 ); err != nil { 77 t.Fatal(err) 78 } 79 80 if err := repeatRunE( 81 ctx, c, node, "set python3.7 as default", ` 82 sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.5 1 83 sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 2 84 sudo update-alternatives --config python3`, 85 ); err != nil { 86 t.Fatal(err) 87 } 88 89 if err := repeatRunE( 90 ctx, c, node, "install pip", 91 `curl https://bootstrap.pypa.io/get-pip.py | sudo -H python3.7`, 92 ); err != nil { 93 t.Fatal(err) 94 } 95 96 if err := repeatRunE( 97 ctx, 98 c, 99 node, 100 "install pytest", 101 // Unpin pytest once sqlalchemy rel_1_3_16 is released (https://github.com/sqlalchemy/sqlalchemy/issues/5201) 102 `sudo pip3 install --upgrade --force-reinstall setuptools pytest==5.3.5 pytest-xdist psycopg2`, 103 ); err != nil { 104 t.Fatal(err) 105 } 106 107 if err := repeatRunE( 108 ctx, c, node, "remove old sqlalchemy-cockroachdb", `sudo rm -rf /mnt/data1/sqlalchemy-cockroachdb`, 109 ); err != nil { 110 t.Fatal(err) 111 } 112 113 if err := repeatGitCloneE( 114 ctx, 115 t.l, 116 c, 117 "https://github.com/cockroachdb/sqlalchemy-cockroachdb.git", 118 "/mnt/data1/sqlalchemy-cockroachdb", 119 "master", 120 node, 121 ); err != nil { 122 t.Fatal(err) 123 } 124 125 t.Status("installing sqlalchemy-cockroachdb") 126 if err := repeatRunE( 127 ctx, c, node, "installing sqlalchemy=cockroachdb", 128 `cd /mnt/data1/sqlalchemy-cockroachdb && sudo python3 setup.py install`, 129 ); err != nil { 130 t.Fatal(err) 131 } 132 133 if err := repeatRunE( 134 ctx, c, node, "remove old sqlalchemy", `sudo rm -rf /mnt/data1/sqlalchemy`, 135 ); err != nil { 136 t.Fatal(err) 137 } 138 139 if err := repeatGitCloneE( 140 ctx, 141 t.l, 142 c, 143 "https://github.com/sqlalchemy/sqlalchemy.git", 144 "/mnt/data1/sqlalchemy", 145 latestTag, 146 node, 147 ); err != nil { 148 t.Fatal(err) 149 } 150 151 t.Status("building sqlalchemy") 152 if err := repeatRunE( 153 ctx, c, node, "building sqlalchemy", `cd /mnt/data1/sqlalchemy && python3 setup.py build`, 154 ); err != nil { 155 t.Fatal(err) 156 } 157 158 blacklistName, expectedFailures, ignoredlistName, ignoredlist := sqlAlchemyBlacklists.getLists(version) 159 if expectedFailures == nil { 160 t.Fatalf("No sqlalchemy blacklist defined for cockroach version %s", version) 161 } 162 c.l.Printf("Running cockroach version %s, using blacklist %s, using ignoredlist %s", 163 version, blacklistName, ignoredlistName) 164 165 t.Status("running sqlalchemy test suite") 166 // Note that this is expected to return an error, since the test suite 167 // will fail. And it is safe to swallow it here. 168 rawResults, _ := c.RunWithBuffer(ctx, t.l, node, 169 `cd /mnt/data1/sqlalchemy/ && pytest -s --maxfail=0 `+ 170 `--dburi=cockroachdb://root@localhost:26257/defaultdb?sslmode=disable `+ 171 `test/dialect/test_suite.py`) 172 173 t.Status("collating the test results") 174 c.l.Printf("Test Results: %s", rawResults) 175 176 // Find all the failed and errored tests. 177 results := newORMTestsResults() 178 179 scanner := bufio.NewScanner(bytes.NewReader(rawResults)) 180 for scanner.Scan() { 181 match := sqlAlchemyResultRegex.FindStringSubmatch(scanner.Text()) 182 if match == nil { 183 continue 184 } 185 test, result := match[1], match[2] 186 pass := result == "PASSED" || strings.Contains(result, "failed as expected") 187 skipped := result == "SKIPPED" 188 results.allTests = append(results.allTests, test) 189 190 ignoredIssue, expectedIgnored := ignoredlist[test] 191 issue, expectedFailure := expectedFailures[test] 192 switch { 193 case expectedIgnored: 194 results.results[test] = fmt.Sprintf("--- SKIP: %s due to %s (expected)", test, ignoredIssue) 195 results.ignoredCount++ 196 case skipped && expectedFailure: 197 results.results[test] = fmt.Sprintf("--- SKIP: %s (unexpected)", test) 198 results.unexpectedSkipCount++ 199 case skipped: 200 results.results[test] = fmt.Sprintf("--- SKIP: %s (expected)", test) 201 results.skipCount++ 202 case pass && !expectedFailure: 203 results.results[test] = fmt.Sprintf("--- PASS: %s (expected)", test) 204 results.passExpectedCount++ 205 case pass && expectedFailure: 206 results.results[test] = fmt.Sprintf("--- PASS: %s - %s (unexpected)", 207 test, maybeAddGithubLink(issue), 208 ) 209 results.passUnexpectedCount++ 210 case !pass && expectedFailure: 211 results.results[test] = fmt.Sprintf("--- FAIL: %s - %s (expected)", 212 test, maybeAddGithubLink(issue), 213 ) 214 results.failExpectedCount++ 215 results.currentFailures = append(results.currentFailures, test) 216 case !pass && !expectedFailure: 217 results.results[test] = fmt.Sprintf("--- FAIL: %s (unexpected)", test) 218 results.failUnexpectedCount++ 219 results.currentFailures = append(results.currentFailures, test) 220 } 221 results.runTests[test] = struct{}{} 222 } 223 224 results.summarizeAll( 225 t, "sqlalchemy" /* ormName */, blacklistName, expectedFailures, version, latestTag) 226 } 227 228 r.Add(testSpec{ 229 Name: "sqlalchemy", 230 Owner: OwnerAppDev, 231 Cluster: makeClusterSpec(1), 232 MinVersion: "v2.1.0", 233 Tags: []string{`default`, `orm`}, 234 Run: func(ctx context.Context, t *test, c *cluster) { 235 runSQLAlchemy(ctx, t, c) 236 }, 237 }) 238 }