func main() { // Print action if steps > 0 { log.Printf("applying migrations...") } else if steps == -1 { log.Printf("rolling back by 1...") } else if steps < 0 { log.Printf("reset. rolling back all migrations...") } // Parse migrations stamps := []int{} ups := map[int]reflect.Method{} downs := map[int]reflect.Method{} structVal := reflect.ValueOf(&M{}) for i := 0; i < structVal.NumMethod(); i++ { method := structVal.Type().Method(i) if c := strings.Split(method.Name, "_"); len(c) >= 3 { stamp, _ := strconv.Atoi(c[len(c)-2]) if c[len(c)-1] == "Up" { ups[stamp] = method stamps = append(stamps, stamp) } else { downs[stamp] = method } } } sort.Ints(stamps) // Open hood hd, err := hood.Open(driver, source) if err != nil { panic(err) } hd.Log = true // Create migration table if necessary tx := hd.Begin() tx.CreateTableIfNotExists(&Migrations{}) err = tx.Commit() if err != nil { panic(err) } // Check if any previous migrations have been run var rows []Migrations err = hd.Find(&rows) if err != nil { panic(err) } if len(rows) > 1 { panic("invalid migrations table") } info := Migrations{} if len(rows) > 0 { info = rows[0] } // Apply cur := 0 count := 0 if steps > 0 { for _, stamp := range stamps { if stamp > info.Current { if cur++; cur <= steps { apply(stamp, stamp, &count, hd, &info, structVal, ups[stamp]) } } } } else if steps < 0 { for i := len(stamps) - 1; i >= 0; i-- { stamp := stamps[i] next := 0 if i > 0 { next = stamps[i-1] } if stamp <= info.Current { if cur--; cur >= steps { apply(stamp, next, &count, hd, &info, structVal, downs[stamp]) } } } } if steps > 0 { log.Printf("applied %d migrations", count) } else if steps < 0 { log.Printf("rolled back %d migrations", count) } log.Printf("generating new schema... %s", schemaPath) dry := hood.Dry() for _, ts := range stamps { if ts <= info.Current { method := ups[ts] method.Func.Call([]reflect.Value{structVal, reflect.ValueOf(dry)}) } } err = ioutil.WriteFile(schemaPath, []byte(dry.GoSchema()), 0666) if err != nil { panic(err) } err = exec.Command("go", "fmt", schemaPath).Run() if err != nil { panic(err) } log.Printf("wrote schema %s", schemaPath) log.Printf("done.") }
func TestTagApi(t *testing.T) { tests := []TestTagStruct{ { First: &TestTag{ Request: "GET", Url: "http://localhost/api/tags", Status: 200, Body: `[]`, }, }, { First: &TestTag{ Request: "POST", Url: "http://localhost/api/tags", Input: &map[string]string{ "name": "a", }, Status: 200, }, Last: &TestTag{ Request: "GET", Url: "http://localhost/api/tags", Input: nil, Status: 200, Result: &api.Tag{ Name: "a", Weight: 20, }, }, }, } // db, err := sql.Open(dbconf.Driver, dbconf.Source) db, err := hood.Open("postgres", "user=postgres dbname=indata_test host=192.168.0.10 sslmode=disable") if err != nil { log.Fatal(err) } serviceApi := api.Api{Db: db} rapi := rest.NewApi() rapi.Use(rest.DefaultCommonStack...) // rapi.Use(&rest.AccessLogApacheMiddleware{}) // rapi.Use(&rest.GzipMiddleware{}) rapi.Use(&rest.ContentTypeCheckerMiddleware{}) router, err := rest.MakeRouter( rest.Get("/tags", serviceApi.GetAllTags), rest.Post("/tags", serviceApi.PostTag), rest.Get("/tags/:name", serviceApi.GetTag), rest.Post("/tags/:name", serviceApi.UpdateTag), rest.Delete("/tags/:name", serviceApi.DeleteTag), ) if err != nil { log.Fatal(err) } rapi.SetApp(router) for _, testVars := range tests { // Start a transaction tx := db.Begin() tx.DropTableIfExists(api.Tag{}) tx.DropTableIfExists(api.Contact{}) tx.DropTableIfExists(api.TagContact{}) tx.CreateTableIfNotExists(api.Tag{}) tx.CreateTableIfNotExists(api.Contact{}) tx.CreateTableIfNotExists(api.TagContact{}) // Commit changes err = tx.Commit() if err != nil { log.Println(err) } hndl := rapi.MakeHandler() handler := http.StripPrefix("/api", hndl) // recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/tags/notfound", nil)) // recorded.CodeIs(404) // recorded.ContentTypeIsJson() // recorded.BodyIs("{\n \"Error\": \"Resource not found\"\n}") // recorded = test.RunRequest(t, &handler, test.MakeSimpleRequest("GET", "http://1.2.3.4/user-notfound", nil)) // recorded.CodeIs(404) // recorded.ContentTypeIsJson() // recorded.BodyIs(`{"Error":"Resource not found"}`) log.Printf("%s request to %s ", testVars.First.Request, testVars.First.Url) recorded := test.RunRequest(t, handler, test.MakeSimpleRequest(testVars.First.Request, testVars.First.Url, testVars.First.Input)) recorded.CodeIs(testVars.First.Status) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() log.Printf("body %#v", recorded.Recorder.Body.String()) if testVars.First.Body != "" { recorded.BodyIs(testVars.First.Body) } if testVars.Last != nil { log.Printf("%s request to %s ", testVars.Last.Request, testVars.Last.Url) recorded := test.RunRequest(t, handler, test.MakeSimpleRequest(testVars.Last.Request, testVars.Last.Url, testVars.Last.Input)) recorded.CodeIs(testVars.Last.Status) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() if testVars.Last.Result != nil { var tags []api.Tag err = recorded.DecodeJsonPayload(&tags) log.Printf("tags %#v", tags) if len(tags) != 1 { t.Errorf(`Expected one element and got %d`, len(tags)) } if testVars.Last.Result.Name != "" { if tags[0].Name != testVars.Last.Result.Name { t.Errorf(`Expected tag name "%s"`, testVars.Last.Result.Name) } } // if ok := testVars.Last.Result.Weight; ok { // if testVars.Last.Result.Weight { if tags[0].Weight != testVars.Last.Result.Weight { t.Errorf(`Expected tag weight "%s"`, testVars.Last.Result.Weight) } // } // } } } } // // recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/tags", nil)) // recorded.CodeIs(200) // recorded.ContentTypeIsJson() // // recorded.ContentEncodingIsGzip() // // var tags []api.Tag // err = recorded.DecodeJsonPayload(&tags) // // if len(tags) != 1 { // t.Errorf(`Expected one element and got %d`, len(tags)) // } // // if tags[0].Name != "a" { // t.Error(`Expected tag name "a"`) // } // // recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("DELETE", "http://localhost/api/tags/"+tags[0].Name, nil)) // recorded.CodeIs(200) // recorded.ContentTypeIsJson() // // recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/tags", nil)) // recorded.CodeIs(200) // recorded.ContentTypeIsJson() // // recorded.ContentEncodingIsGzip() // recorded.BodyIs(`[]`) }
func main() { flag.Parse() p, err := osext.ExecutableFolder() if err != nil { log.Fatal(err) } dbconf, err := load(path.Join(p, "db", "config.json"), *flagEnv) if err != nil { log.Fatal(err) } // db, err := sql.Open(dbconf.Driver, dbconf.Source) db, err := hood.Open(dbconf.Driver, dbconf.Source) if err != nil { log.Fatal(err) } // svmw := semVerMiddleware{ // MinVersion: "1.0.0", // MaxVersion: "1.0.0", // } serviceApi := api.Api{Db: db} rapi := rest.NewApi() rapi.Use(rest.DefaultDevStack...) router, err := rest.MakeRouter( rest.Get("/tags", serviceApi.GetAllTags), rest.Post("/tags", serviceApi.PostTag), rest.Get("/tags/:name", serviceApi.GetTag), rest.Post("/tags/:name", serviceApi.UpdateTag), rest.Delete("/tags/:name", serviceApi.DeleteTag), rest.Get("/contacts", serviceApi.GetAllContacts), rest.Post("/contacts", serviceApi.PostContact), rest.Get("/contacts/:name", serviceApi.GetContact), rest.Post("/contacts/:name", serviceApi.UpdateContact), rest.Delete("/contacts/:name", serviceApi.DeleteContact), // rest.Get("/#version/message", svmw.MiddlewareFunc( // func(w rest.ResponseWriter, req *rest.Request) { // version := req.Env["VERSION"].(*semver.Version) // if version.Major == 2 { // // http://en.wikipedia.org/wiki/Second-system_effect // w.WriteJson(map[string]string{ // "Body": "Hello broken World!", // }) // } else { // w.WriteJson(map[string]string{ // "Body": "Hello World!", // }) // } // }, // )), ) if err != nil { log.Fatal(err) } rapi.SetApp(router) http.Handle("/api/", http.StripPrefix("/api", rapi.MakeHandler())) log.Println("Started") log.Fatal(http.ListenAndServe(":8080", nil)) }
func TestContactApi(t *testing.T) { // db, err := sql.Open(dbconf.Driver, dbconf.Source) db, err := hood.Open("postgres", "user=postgres dbname=indata_test host=192.168.0.10 sslmode=disable") if err != nil { log.Fatal(err) } serviceApi := api.Api{Db: db} rapi := rest.NewApi() rapi.Use(rest.DefaultDevStack...) router, err := rest.MakeRouter( rest.Get("/contacts", serviceApi.GetAllContacts), rest.Post("/contacts", serviceApi.PostContact), rest.Get("/contacts/:name", serviceApi.GetContact), rest.Post("/contacts/:name", serviceApi.UpdateContact), rest.Delete("/contacts/:name", serviceApi.DeleteContact), ) if err != nil { log.Fatal(err) } rapi.SetApp(router) // Start a transaction tx := db.Begin() tx.DropTableIfExists(api.Tag{}) tx.DropTableIfExists(api.Contact{}) tx.DropTableIfExists(api.TagContact{}) tx.CreateTableIfNotExists(api.Tag{}) tx.CreateTableIfNotExists(api.Contact{}) tx.CreateTableIfNotExists(api.TagContact{}) // Commit changes err = tx.Commit() if err != nil { log.Println(err) } handler := http.StripPrefix("/api", rapi.MakeHandler()) recorded := test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/contacts", nil)) recorded.CodeIs(200) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() recorded.BodyIs(`[]`) recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("POST", "http://localhost/api/contacts", &map[string]string{ "name": "a", "title": "a", "description": "a", })) recorded.CodeIs(200) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/contacts", nil)) recorded.CodeIs(200) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() var contacts []api.Contact err = recorded.DecodeJsonPayload(&contacts) if len(contacts) != 1 { t.Errorf(`Expected one element and got %d`, len(contacts)) } if contacts[0].Name != "a" { t.Error(`Expected contact name "a"`) } spew.Dump(contacts) recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("DELETE", "http://localhost/api/contacts/"+contacts[0].Name, nil)) recorded.CodeIs(200) recorded.ContentTypeIsJson() recorded = test.RunRequest(t, handler, test.MakeSimpleRequest("GET", "http://localhost/api/contacts", nil)) recorded.CodeIs(200) recorded.ContentTypeIsJson() // recorded.ContentEncodingIsGzip() recorded.BodyIs(`[]`) }