Skip to content

Commit b89e37a

Browse files
committed
testing: Introduce original suite of tests to verify ORMs
1 parent b1c1b64 commit b89e37a

File tree

8 files changed

+500
-65
lines changed

8 files changed

+500
-65
lines changed

Makefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2016 The Cockroach Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
# implied. See the License for the specific language governing
13+
# permissions and limitations under the License. See the AUTHORS file
14+
# for names of contributors.
15+
#
16+
# Author: Nathan VanBenschoten ([email protected])
17+
18+
GO ?= go
19+
20+
.PHONY: all
21+
all: test
22+
23+
.PHONY: test
24+
test:
25+
$(GO) test -v -i ./testing
26+
$(GO) test -v ./testing
27+
28+
.PHONY: deps
29+
deps:
30+
$(GO) get -d -t ./...

go/gorm/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
#
1616
# Author: Nathan VanBenschoten ([email protected])
1717

18+
ifneq ($(ADDR),)
19+
ADDRFLAG = -addr=$(ADDR)
20+
endif
21+
1822
.PHONY: start
1923
start:
2024
@go build
21-
@./gorm
25+
@./gorm $(ADDRFLAG)

go/gorm/main.go

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,42 @@
11
package main
22

33
import (
4+
"flag"
45
"log"
56
"net/http"
67

8+
"github.com/cockroachdb/examples-orms/go/gorm/model"
79
"github.com/jinzhu/gorm"
810
_ "github.com/jinzhu/gorm/dialects/postgres"
911
"github.com/julienschmidt/httprouter"
1012
)
1113

14+
var (
15+
addr = flag.String("addr", "postgresql://root@localhost:26257/company_gorm?sslmode=disable", "the address of the database")
16+
)
17+
1218
func main() {
13-
db := setupDB()
19+
flag.Parse()
20+
21+
db := setupDB(*addr)
1422
defer db.Close()
1523

1624
router := httprouter.New()
1725

1826
server := NewServer(db)
1927
server.RegisterRouter(router)
2028

21-
log.Fatal(http.ListenAndServe(":8080", router))
29+
log.Fatal(http.ListenAndServe(":6543", router))
2230
}
2331

24-
func setupDB() *gorm.DB {
25-
db, err := gorm.Open("postgres", "postgresql://root@localhost:26257/company_gorm?sslmode=disable")
32+
func setupDB(addr string) *gorm.DB {
33+
db, err := gorm.Open("postgres", addr)
2634
if err != nil {
2735
panic("failed to connect database")
2836
}
2937

3038
// Migrate the schema
31-
migrateDB(db)
32-
33-
// Initialize the database if it's empty.
34-
var count int
35-
db.Model(&Product{}).Count(&count)
36-
if count == 0 {
37-
// Create Products.
38-
p1 := "P1"
39-
p2 := "P2"
40-
db.Create(&Product{Name: &p1, Price: 22.2})
41-
db.Create(&Product{Name: &p2, Price: 2.2})
42-
43-
// Create Customers.
44-
john := "John"
45-
fred := "Fred"
46-
db.Create(&Customer{Name: &john})
47-
db.Create(&Customer{Name: &fred})
48-
49-
// Create an Order.
50-
{
51-
tx := db.Begin()
52-
53-
var product Product
54-
tx.First(&product, "name = ?", "P2")
55-
56-
var customer Customer
57-
tx.First(&customer, "name = ?", "Fred")
58-
59-
tx.Create(&Order{
60-
Subtotal: product.Price,
61-
Customer: customer,
62-
Products: []Product{product},
63-
})
64-
tx.Commit()
65-
}
66-
}
39+
db.AutoMigrate(&model.Customer{}, &model.Order{}, &model.Product{})
6740

6841
return db
6942
}
Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
package main
2-
3-
import "github.com/jinzhu/gorm"
1+
package model
42

53
// Customer is a model in the "customers" table.
64
type Customer struct {
@@ -25,7 +23,3 @@ type Product struct {
2523
Name *string `gorm:"not null;unique"`
2624
Price float64 `gorm:"type:decimal(18,2)"`
2725
}
28-
29-
func migrateDB(db *gorm.DB) {
30-
db.AutoMigrate(&Customer{}, &Order{}, &Product{})
31-
}

go/gorm/server.go

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"net/http"
77

8+
"github.com/cockroachdb/examples-orms/go/gorm/model"
89
"github.com/jinzhu/gorm"
910
"github.com/julienschmidt/httprouter"
1011
)
@@ -42,7 +43,7 @@ func (s *Server) RegisterRouter(router *httprouter.Router) {
4243
}
4344

4445
func (s *Server) getCustomers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
45-
var customers []Customer
46+
var customers []model.Customer
4647
if err := s.db.Find(&customers).Error; err != nil {
4748
http.Error(w, err.Error(), errToStatusCode(err))
4849
} else {
@@ -51,7 +52,7 @@ func (s *Server) getCustomers(w http.ResponseWriter, r *http.Request, _ httprout
5152
}
5253

5354
func (s *Server) createCustomer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
54-
var customer Customer
55+
var customer model.Customer
5556
if err := json.NewDecoder(r.Body).Decode(&customer); err != nil {
5657
http.Error(w, err.Error(), errToStatusCode(err))
5758
return
@@ -65,7 +66,7 @@ func (s *Server) createCustomer(w http.ResponseWriter, r *http.Request, ps httpr
6566
}
6667

6768
func (s *Server) getCustomer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
68-
var customer Customer
69+
var customer model.Customer
6970
if err := s.db.Find(&customer, ps.ByName("customerID")).Error; err != nil {
7071
http.Error(w, err.Error(), errToStatusCode(err))
7172
} else {
@@ -74,7 +75,7 @@ func (s *Server) getCustomer(w http.ResponseWriter, r *http.Request, ps httprout
7475
}
7576

7677
func (s *Server) updateCustomer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
77-
var customer Customer
78+
var customer model.Customer
7879
if err := json.NewDecoder(r.Body).Decode(&customer); err != nil {
7980
http.Error(w, err.Error(), errToStatusCode(err))
8081
return
@@ -90,7 +91,7 @@ func (s *Server) updateCustomer(w http.ResponseWriter, r *http.Request, ps httpr
9091

9192
func (s *Server) deleteCustomer(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
9293
customerID := ps.ByName("customerID")
93-
req := s.db.Delete(Customer{}, "ID = ?", customerID)
94+
req := s.db.Delete(model.Customer{}, "ID = ?", customerID)
9495
if err := req.Error; err != nil {
9596
http.Error(w, err.Error(), errToStatusCode(err))
9697
} else if req.RowsAffected == 0 {
@@ -101,7 +102,7 @@ func (s *Server) deleteCustomer(w http.ResponseWriter, r *http.Request, ps httpr
101102
}
102103

103104
func (s *Server) getProducts(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
104-
var products []Product
105+
var products []model.Product
105106
if err := s.db.Find(&products).Error; err != nil {
106107
http.Error(w, err.Error(), errToStatusCode(err))
107108
} else {
@@ -110,7 +111,7 @@ func (s *Server) getProducts(w http.ResponseWriter, r *http.Request, _ httproute
110111
}
111112

112113
func (s *Server) createProduct(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
113-
var product Product
114+
var product model.Product
114115
if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
115116
http.Error(w, err.Error(), errToStatusCode(err))
116117
return
@@ -124,7 +125,7 @@ func (s *Server) createProduct(w http.ResponseWriter, r *http.Request, ps httpro
124125
}
125126

126127
func (s *Server) getProduct(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
127-
var product Product
128+
var product model.Product
128129
if err := s.db.Find(&product, ps.ByName("productID")).Error; err != nil {
129130
http.Error(w, err.Error(), errToStatusCode(err))
130131
} else {
@@ -133,7 +134,7 @@ func (s *Server) getProduct(w http.ResponseWriter, r *http.Request, ps httproute
133134
}
134135

135136
func (s *Server) updateProduct(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
136-
var product Product
137+
var product model.Product
137138
if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
138139
http.Error(w, err.Error(), errToStatusCode(err))
139140
return
@@ -149,7 +150,7 @@ func (s *Server) updateProduct(w http.ResponseWriter, r *http.Request, ps httpro
149150

150151
func (s *Server) deleteProduct(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
151152
productID := ps.ByName("productID")
152-
req := s.db.Delete(Product{}, "ID = ?", productID)
153+
req := s.db.Delete(model.Product{}, "ID = ?", productID)
153154
if err := req.Error; err != nil {
154155
http.Error(w, err.Error(), errToStatusCode(err))
155156
} else if req.RowsAffected == 0 {
@@ -160,7 +161,7 @@ func (s *Server) deleteProduct(w http.ResponseWriter, r *http.Request, ps httpro
160161
}
161162

162163
func (s *Server) getOrders(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
163-
var orders []Order
164+
var orders []model.Order
164165
if err := s.db.Preload("Customer").Preload("Products").Find(&orders).Error; err != nil {
165166
http.Error(w, err.Error(), errToStatusCode(err))
166167
} else {
@@ -169,7 +170,7 @@ func (s *Server) getOrders(w http.ResponseWriter, r *http.Request, _ httprouter.
169170
}
170171

171172
func (s *Server) createOrder(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
172-
var order Order
173+
var order model.Order
173174
if err := json.NewDecoder(r.Body).Decode(&order); err != nil {
174175
http.Error(w, err.Error(), errToStatusCode(err))
175176
return
@@ -183,7 +184,7 @@ func (s *Server) createOrder(w http.ResponseWriter, r *http.Request, ps httprout
183184
}
184185

185186
func (s *Server) getOrder(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
186-
var order Order
187+
var order model.Order
187188
if err := s.db.Preload("Customer").Preload("Products").Find(&order, ps.ByName("orderID")).Error; err != nil {
188189
http.Error(w, err.Error(), errToStatusCode(err))
189190
} else {
@@ -192,7 +193,7 @@ func (s *Server) getOrder(w http.ResponseWriter, r *http.Request, ps httprouter.
192193
}
193194

194195
func (s *Server) updateOrder(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
195-
var order Order
196+
var order model.Order
196197
if err := json.NewDecoder(r.Body).Decode(&order); err != nil {
197198
http.Error(w, err.Error(), errToStatusCode(err))
198199
return
@@ -208,7 +209,7 @@ func (s *Server) updateOrder(w http.ResponseWriter, r *http.Request, ps httprout
208209

209210
func (s *Server) deleteOrder(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
210211
orderID := ps.ByName("orderID")
211-
req := s.db.Delete(Order{}, "ID = ?", orderID)
212+
req := s.db.Delete(model.Order{}, "ID = ?", orderID)
212213
if err := req.Error; err != nil {
213214
http.Error(w, err.Error(), errToStatusCode(err))
214215
} else if req.RowsAffected == 0 {
@@ -221,7 +222,7 @@ func (s *Server) deleteOrder(w http.ResponseWriter, r *http.Request, ps httprout
221222
func (s *Server) addProductToOrder(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
222223
tx := s.db.Begin()
223224

224-
var order Order
225+
var order model.Order
225226
orderID := ps.ByName("orderID")
226227
if err := tx.Preload("Products").First(&order, orderID).Error; err != nil {
227228
tx.Rollback()
@@ -237,7 +238,7 @@ func (s *Server) addProductToOrder(w http.ResponseWriter, r *http.Request, ps ht
237238
return
238239
}
239240

240-
var addedProduct Product
241+
var addedProduct model.Product
241242
if err := tx.First(&addedProduct, productID).Error; err != nil {
242243
tx.Rollback()
243244
http.Error(w, err.Error(), errToStatusCode(err))

testing/api_handler.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package testing
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"net/http"
7+
8+
"github.com/cockroachdb/examples-orms/go/gorm/model"
9+
)
10+
11+
const (
12+
applicationAddr = "http://localhost:6543"
13+
14+
customersPath = applicationAddr + "/customer"
15+
ordersPath = applicationAddr + "/order"
16+
productsPath = applicationAddr + "/product"
17+
18+
jsonContentType = "application/json"
19+
)
20+
21+
// apiHandler takes care of communicating with the application api. It uses GORM's models
22+
// for convenient JSON marshalling/unmarshalling, but this format should be the same
23+
// across all ORMs.
24+
type apiHandler struct{}
25+
26+
func (apiHandler) queryCustomers() ([]model.Customer, error) {
27+
var customers []model.Customer
28+
if err := getJSON(customersPath, &customers); err != nil {
29+
return nil, err
30+
}
31+
return cleanCustomers(customers), nil
32+
}
33+
func (apiHandler) queryProducts() ([]model.Product, error) {
34+
var products []model.Product
35+
if err := getJSON(productsPath, &products); err != nil {
36+
return nil, err
37+
}
38+
return cleanProducts(products), nil
39+
}
40+
41+
func (apiHandler) createCustomer(name string) error {
42+
customer := model.Customer{Name: &name}
43+
return postJSONData(customersPath, customer)
44+
}
45+
func (apiHandler) createProduct(name string, price float64) error {
46+
product := model.Product{Name: &name, Price: price}
47+
return postJSONData(productsPath, product)
48+
}
49+
50+
func getJSON(path string, result interface{}) error {
51+
resp, err := http.Get(path)
52+
if err != nil {
53+
return err
54+
}
55+
defer resp.Body.Close()
56+
return json.NewDecoder(resp.Body).Decode(result)
57+
}
58+
59+
func postJSONData(path string, body interface{}) error {
60+
var bodyBuf bytes.Buffer
61+
if err := json.NewEncoder(&bodyBuf).Encode(body); err != nil {
62+
return err
63+
}
64+
65+
_, err := http.Post(path, jsonContentType, &bodyBuf)
66+
return err
67+
}
68+
69+
// These functions clean any non-deterministic fields, such as IDs that are
70+
// generated upon row creation.
71+
func cleanCustomers(customers []model.Customer) []model.Customer {
72+
for i := range customers {
73+
customers[i].ID = 0
74+
}
75+
return customers
76+
}
77+
func cleanProducts(products []model.Product) []model.Product {
78+
for i := range products {
79+
products[i].ID = 0
80+
}
81+
return products
82+
}

0 commit comments

Comments
 (0)