func (this *Member) CheckPass(email string, password string) int { //验证登录信息 err := memberC.Find(bson.M{"e": email}).One(&this) if err != nil { //处理错误 } if bson.Now().Before(this.StopTime) { //锁定时间还没过 return 0 //处于锁定状态 } if this.Password == password { this.Error = 6 this.Update(bson.M{"$set": bson.M{"er": this.Error}}) return 1 //通过验证 } else { if this.Error <= 1 { this.Error = 6 minute := time.Duration(10) * time.Minute this.StopTime = bson.Now().Add(minute) this.Update(bson.M{"$set": bson.M{"er": this.Error, "st": this.StopTime}}) return 2 //用户名或密码不正确 } else { this.Error-- this.Update(bson.M{"$set": bson.M{"er": this.Error}}) return 2 //用户名或密码不正确 } } }
func (tag *TagWrapper) SetTag() error { c := DB.C("tags") var err error flag := false for _, v := range Tags { if tag.Name == v.Name { v.ArticleIds = append(v.ArticleIds, tag.ArticleIds...) removeDuplicate(&v.ArticleIds) v.Count = len(v.ArticleIds) v.ModifiedTime = bson.Now() err = c.UpdateId(v.Id_, v) flag = true break } } if !flag { tag.Id_ = bson.NewObjectId() tag.CreatedTime = bson.Now() tag.ModifiedTime = bson.Now() Tags = append(Tags, *tag) err = c.Insert(tag) } SetAppTags() return err }
func (this *RootArticleRouter) Post() { id := this.GetString("id") if len(this.Input()) == 1 { //删除操作 models.DeleteArticle(&bson.M{"_id": bson.ObjectIdHex(id)}) this.Data["json"] = true this.ServeJson(true) } else { nodename := this.GetString("selectnode") name := this.GetString("name") title := this.GetString("title") content := this.GetString("content") isThumbnail, _ := this.GetBool("isThumbnail") featuredPicURL := this.GetString("featuredPicURL") tags := this.GetStrings("tags") author, _ := this.GetSession("username").(string) cat := models.GetCategoryNodeName(nodename) if name == "" { name = strconv.Itoa(int(bson.Now().UnixNano())) } if id != "" { //更新 article, _ := models.GetArticle(&bson.M{"_id": bson.ObjectIdHex(id)}) article.CName = cat.Name article.NName = nodename article.Name = name article.Author = author article.Title = title article.Tags = tags article.FeaturedPicURL = featuredPicURL article.ModifiedTime = bson.Now() article.Text = template.HTML(content) article.IsThumbnail = isThumbnail article.SetSummary() article.UpdateArticle() this.Redirect("/root/article", 302) } else { //创建 article := models.Article{ CName: cat.Name, NName: nodename, Name: name, Author: author, Title: title, Tags: tags, FeaturedPicURL: featuredPicURL, CreatedTime: bson.Now(), ModifiedTime: bson.Now(), Text: template.HTML(content), IsThumbnail: isThumbnail, } article.SetSummary() article.CreatArticle() go Publish(&article) this.Redirect("/root/article", 302) } } }
func (this *RootNodeRouter) Post() { if len(this.Input()) == 2 { //删除操作 cid := this.GetString("id") nname := this.GetString("nname") for _, v := range models.Categories { if v.Id_.Hex() == cid { for in, va := range v.Nodes { if va.Name == nname { v.Nodes = append(v.Nodes[:in], v.Nodes[(in+1):]...) break } } v.UpdateCategory() break } } this.Data["json"] = true this.ServeJson(true) } else { categoryid := this.GetString("selectcategory") name := this.GetString("name") title := this.GetString("title") content := this.GetString("content") if name == "" { name = strconv.Itoa(int(bson.Now().UnixNano())) } for _, v := range models.Categories { if v.Id_.Hex() == categoryid { flag := false for _, va := range v.Nodes { if va.Name == name { //更新 va.Title = title va.Content = content va.UpdatedTime = bson.Now() flag = true break } } if !flag { //添加 node := models.Node{ Name: name, Title: title, Content: content, CreatedTime: bson.Now(), UpdatedTime: bson.Now(), } v.Nodes = append(v.Nodes, node) } v.UpdateCategory() break } } this.Redirect("/root/node", 302) } }
func (this *Member) Insert() string { //插入数据 this.Id = bson.NewObjectId() this.FirstTime = bson.Now() this.LastTime = bson.Now() err := memberC.Insert(this) if err != nil { panic(err) } return bson.ObjectId.Hex(this.Id) }
func (s *StoreSuite) TestLockUpdatesExpires(c *C) { urlA := charm.MustParseURL("cs:oneiric/wordpress-a") urlB := charm.MustParseURL("cs:oneiric/wordpress-b") urls := []*charm.URL{urlA, urlB} // Initiate an update of B only to force a partial conflict. lock1, err := s.store.LockUpdates(urls[1:]) c.Assert(err, IsNil) // Hack time to force an expiration. locks := s.Session.DB("juju").C("locks") selector := bson.M{"_id": urlB.String()} update := bson.M{"time": bson.Now().Add(-store.UpdateTimeout - 10e9)} err = locks.Update(selector, update) c.Check(err, IsNil) // Works due to expiration of previous lock. lock2, err := s.store.LockUpdates(urls) c.Assert(err, IsNil) defer lock2.Unlock() // The expired lock was forcefully killed. Unlocking it must // not interfere with lock2 which is still alive. lock1.Unlock() // The above statement was a NOOP and lock2 is still in effect, // so attempting another lock must necessarily fail. lock3, err := s.store.LockUpdates(urls) c.Check(err, Equals, store.ErrUpdateConflict) c.Check(lock3, IsNil) }
func (s *S) TestNow(c *C) { before := time.Now() time.Sleep(1e6) now := bson.Now() time.Sleep(1e6) after := time.Now() c.Assert(now.After(before) && now.Before(after), Equals, true, Commentf("now=%s, before=%s, after=%s", now, before, after)) }
func TestReplyer(t *testing.T) { setUp(t) defer tearDown(t) var obj = Reply{ ID: "1234_abcxxxxxxxxxxxx", Error: "Errare humanum est", StatusCode: 102, Header: make(http.Header), // So it is retrieved from mongoDB. nil does not work Trailer: make(http.Header), // So it is retrieved from mongoDB. nil does not work Proto: "protocol", Body: []byte{1, 2, 3, 0, 9, 8, 7}, Done: bson.Now(), Created: bson.Now(), } replyer := &Replyer{Cfg: cfgTest, SessionSeed: sessionTest} db := sessionTest.DB(cfgTest.Database) respColl := db.C(cfgTest.ResponsesColl) respColl.Insert(obj) if err := sessionTest.Fsync(false); err != nil { t.Fatal(err) } request, err := http.NewRequest("GET", "/one/two/three/"+obj.ID, nil) if err != nil { t.Fatal(err) } response := httptest.NewRecorder() replyer.ServeHTTP(response, request) if response.Code != 200 { t.Errorf("response should be 200 for existent reply. reponse.Code %d", response.Code) } if contentType := response.Header().Get("Content-Type"); contentType != "application/json" { t.Errorf("content type of response should be \"application/json\". It is %q", contentType) } var objR = Reply{} err = json.Unmarshal(response.Body.Bytes(), &objR) if err != nil { t.Fatalf("%v : %q", err, response.Body.Bytes()) } if !reflect.DeepEqual(obj, objR) { t.Error("response body should be equal to body reply %#v %#v", obj, objR) } }
func (ts *TestStore) PingSession(s *Session) error { if tss, ok := ts.Sessions[s.Id]; ok { if tss.MachineId == s.MachineId && tss.ClosedAt.Equal(time.Time{}) { tss.LastPing = bson.Now() return nil } } return mgo.ErrNotFound }
func NewInstallation(machineId, xmppvoxVersion string, dosvoxInfo, machineInfo map[string]string) *Installation { return &Installation{ MachineId: machineId, XMPPVOXVersion: xmppvoxVersion, DosvoxInfo: dosvoxInfo, MachineInfo: machineInfo, CreatedAt: bson.Now(), } }
//process recreates the request that should be sent to the target host //it stores the response in the store of replies. func (c *Consumer) process(petition *Petition) { var ( req *http.Request resp *http.Response reply *Reply start = bson.Now() ) db := c.SessionSeed.DB(c.Cfg.Database) petColl := db.C(c.Cfg.Instance + c.Cfg.PetitionsColl) replyColl := db.C(c.Cfg.ResponsesColl) errColl := db.C(c.Cfg.ErrorsColl) mylog.Debugf("processing petition %+v", petition) req, err := petition.Request() if err != nil { mylog.Alert(petition.ID, err) return } mylog.Debugf("restored request %+v", req) mylog.Debug("before making request", petition.ID) resp, err = c.doRequest(req, petition.ID) if err == nil { mylog.Debug("after making request", petition.ID) defer func() { mylog.Debug("closing response body", petition.ID) resp.Body.Close() }() } reply = newReply(resp, petition, err) reply.Created = start mylog.Debugf("created reply %+v", reply) if err != nil || resp.StatusCode < 200 || resp.StatusCode >= 300 { e := errColl.Insert(reply) if e != nil { mylog.Alert("ERROR inserting erroneous reply", petition.ID, err) c.SessionSeed.Refresh() } } mylog.Debugf("before insert reply %+v", reply) err = replyColl.Insert(reply) mylog.Debugf("after insert reply %+v", reply) if err != nil { mylog.Alert("ERROR inserting reply", petition.ID, err) c.SessionSeed.Refresh() } mylog.Debugf("before remove petition %+v", petition) err = petColl.Remove(bson.M{"id": petition.ID}) mylog.Debugf("after remove petition %+v", petition) if err != nil { mylog.Alert("ERROR removing petition", petition.ID, err) c.SessionSeed.Refresh() } }
func NewSession(jid, machineId, xmppvoxVersion string, r *HttpRequest) *Session { return &Session{ Id: bson.NewObjectId(), CreatedAt: bson.Now(), JID: jid, MachineId: machineId, XMPPVOXVersion: xmppvoxVersion, Request: r, } }
func SetTag(tag *TagWrapper) error { c := DB.C("tags") var oldtag TagWrapper err := c.Find(bson.M{"name": tag.Name}).One(&oldtag) if err != nil && err.Error() == "not found" { tag.Id_ = bson.NewObjectId() tag.CreatedTime = bson.Now() tag.ModifiedTime = bson.Now() c.Insert(tag) } else if err != nil { return err } else { oldtag.ArticleIds = append(oldtag.ArticleIds, tag.ArticleIds...) removeDuplicate(&oldtag.ArticleIds) oldtag.Count = len(oldtag.ArticleIds) oldtag.ModifiedTime = bson.Now() c.UpdateId(oldtag.Id_, oldtag) } return nil }
func (m *MongoStore) CloseSession(s *Session) error { updateClosedTime := mgo.Change{ Update: bson.M{"$set": bson.M{"closed_at": bson.Now()}}, ReturnNew: true, } _, err := m.C("sessions").Find(bson.M{ "_id": s.Id, "machine_id": s.MachineId, "closed_at": time.Time{}, }).Apply(updateClosedTime, &s) return err }
func (this *RootCategoryRouter) Post() { id := this.GetString("id") if len(this.Input()) == 1 { //删除操作 models.DeleteCategory(&bson.M{"_id": bson.ObjectIdHex(id)}) this.Data["json"] = true this.ServeJson(true) } else { name := this.GetString("name") title := this.GetString("title") content := this.GetString("content") if name == "" { name = strconv.Itoa(int(bson.Now().UnixNano())) } if id != "" { for _, v := range models.Categories { if v.Id_.Hex() == id { v.Name = name v.Title = title v.Content = content v.UpdatedTime = bson.Now() v.UpdateCategory() break } } } else { cat := models.Category{ Id_: bson.NewObjectId(), Name: name, Title: title, Content: content, CreatedTime: bson.Now(), UpdatedTime: bson.Now(), NodeTime: bson.Now(), } cat.CreatCategory() } this.Redirect("/root/category", 302) } }
// Return an empty calculation func NewCalculation(calculation string) *Calculation { return &Calculation{ Calculation: calculation, OS: "", Language: "", Answer: 0.0, Instance: "", Id: bson.NewObjectId(), Time: bson.Now(), Error: "", Processing: false, } }
func (file *GridFile) insertFile() { hexsum := hex.EncodeToString(file.wsum.Sum(nil)) for file.wpending > 0 { debugf("GridFile %p: waiting for %d pending chunks to insert file", file, file.wpending) file.c.Wait() } if file.err == nil { file.doc.UploadDate = bson.Now() file.doc.MD5 = hexsum file.err = file.gfs.Files.Insert(file.doc) file.gfs.Chunks.EnsureIndexKey("files_id", "n") } }
func (this *IndexController) Prepare() { //查找用户数据 this.isOk = this.member.CheckOne(this.GetString("id"), this.GetString("pass")) if this.isOk { //执行统一逻辑 //如果是第二天第一次登陆 if this.member.LastOperateTime.Year() < bson.Now().Year() || this.member.LastOperateTime.YearDay() < bson.Now().YearDay() { //产生时间(天)跨度 //疲劳恢复满 this.member.NowStamina = this.member.AllStamina //刷新购买商店 this.RefreshShop() } //每20秒恢复一点能量,计算经过的秒数 second := math.Floor(time.Now().Sub(this.member.LastOperateTime).Seconds()) if this.member.NowEnergy+second/20 > this.member.AllEnergy { this.member.NowEnergy = this.member.AllEnergy } else { this.member.NowEnergy += second / 20 } //更新最后操作时间 this.member.LastOperateTime = bson.Now() } }
// LockUpdates acquires a server-side lock for updating a single charm // that is supposed to be made available in all of the provided urls. // If the lock can't be acquired in any of the urls, an error will be // immediately returned. // In the usual case, any locking done is undone when an error happens, // or when l.Unlock is called. If something else goes wrong, the locks // will also expire after the period defined in UpdateTimeout. func (s *Store) LockUpdates(urls []*charm.URL) (l *UpdateLock, err error) { session := s.session.Copy() keys := make([]string, len(urls)) for i := range urls { keys[i] = urls[i].String() } sort.Strings(keys) l = &UpdateLock{keys, session.Locks(), bson.Now()} if err = l.tryLock(); err != nil { session.Close() return nil, err } return l, nil }
func (file *GridFile) completeWrite() { for file.wpending > 0 { debugf("GridFile %p: waiting for %d pending chunks to complete file write", file, file.wpending) file.c.Wait() } if file.err != nil { file.gfs.Chunks.RemoveAll(bson.D{{"files_id", file.doc.Id}}) return } hexsum := hex.EncodeToString(file.wsum.Sum(nil)) file.doc.UploadDate = bson.Now() file.doc.MD5 = hexsum file.err = file.gfs.Files.Insert(file.doc) file.gfs.Chunks.EnsureIndexKey("files_id", "n") }
func saveAuthorization(storage *MongoStorage) (*osin.AuthorizeData, error) { client, err := setClient1234(storage) if err != nil { return &osin.AuthorizeData{}, err } data := &osin.AuthorizeData{ Client: client, Code: "9999", ExpiresIn: 3600, CreatedAt: bson.Now(), RedirectUri: "http://localhost:14000/appauth", } err = storage.SaveAuthorize(data) return data, err }
/* 插入用户 */ func (this *Member) Insert() string { this.Id = bson.NewObjectId() this.LastOperateTime = bson.Now() this.MaxLevel = 1 //最大关卡数初始为1 this.AllStamina = 100 //最大疲劳值初始值为100 this.NowStamina = 100 //当前疲劳值初始值为100 this.AllEnergy = 20 //最大能量初始值为20 this.NowEnergy = 20 //当前能量初始值为20 this.Gold = 100 //金币初始值为100 err := memberC.Insert(this) if err != nil { return "" } return bson.ObjectId.Hex(this.Id) }
func saveAccess(storage *MongoStorage) (*osin.AccessData, error) { authData, err := saveAuthorization(storage) if err != nil { return &osin.AccessData{}, err } data := &osin.AccessData{ Client: authData.Client, AuthorizeData: authData, AccessToken: "9999", RefreshToken: "r9999", ExpiresIn: 3600, CreatedAt: bson.Now(), } err = storage.SaveAccess(data) return data, err }
func (s *WebAPISuite) TestPingSessionTwice(c *C) { nr := s.newSession("*****@*****.**", "00:26:cc:18:be:14", "1.0") id := bson.ObjectIdHex(strings.TrimSpace(nr.Body)) // First PING cr := s.pingSession(id, "00:26:cc:18:be:14") c.Check(cr.StatusCode, Equals, http.StatusOK) session := s.Store.(*TestStore).Sessions[id] lastPingBefore := session.LastPing middleTime := bson.Now() // Second PING cr = s.pingSession(id, "00:26:cc:18:be:14") c.Check(cr.StatusCode, Equals, http.StatusOK) // Check session.LastPing value session = s.Store.(*TestStore).Sessions[id] lastPingAfter := session.LastPing // Check that lastPingBefore <= middleTime <= lastPingAfter c.Check(lastPingBefore.After(middleTime) || middleTime.After(lastPingAfter), Equals, false) }
func main() { logout := log.New(os.Stdout, "MGO: ", log.Lshortfile) mgo.SetLogger(logout) mgo.SetDebug(false) session, err := mgo.Dial("localhost") if err != nil { panic(err) } defer session.Close() db := session.DB("bookdb") coll := db.C("bookcoll") // Insert some books mine := Book{ bson.NewObjectId(), "I never wrote a book", bson.Now(), } coll.Insert(&mine) hpott := Book{ bson.NewObjectId(), "Harry Potter", time.Now(), } coll.Insert(&hpott) var alldocs Books coll.Find(bson.M{}).All(&alldocs) str, _ := json.MarshalIndent(alldocs, "", " ") fmt.Printf("%s\n", str) c, err := coll.Count() fmt.Printf("Total documents: %d\n", c) fmt.Println("Dropping entire collection...") coll.DropCollection() fmt.Println("Done") }
//newReply returns the Reply for the Petition made, the http.Response gotten and the possible error func newReply(resp *http.Response, p *Petition, e error) *Reply { var reply = &Reply{ID: p.ID, Petition: p, TraceID: p.TraceID} if e != nil { reply.Error = e.Error() return reply } reply.StatusCode = resp.StatusCode reply.Proto = resp.Proto reply.Header = resp.Header reply.Trailer = resp.Trailer mylog.Debug("before reading response body", p.ID) body, err := ioutil.ReadAll(resp.Body) if err != nil { mylog.Debugf("error reading response body %v %+v", err, p) reply.Error = e.Error() } else { mylog.Debug("after reading response body", p.ID) reply.Body = body } reply.Done = bson.Now() mylog.Debugf("reply done %+v", reply) return reply }
// tryExpire attempts to remove outdated locks from the database. func (l *UpdateLock) tryExpire(key string) { // Ignore errors. If nothing happens the key will continue locked. l.locks.Remove(bson.D{{"_id", key}, {"time", bson.D{{"$lt", bson.Now().Add(-UpdateTimeout)}}}}) }
func (putr *Putter) Put(event Event) error { eventType := event.Type event.Type = "" // Validate the date and type. if matched, _ := regexp.MatchString(typeRe, eventType); !matched { return errors.New("invalid type") } fmt.Println(event) if event.Time.IsZero() { event.Time = bson.Now() } // If this is a known event type, save immediately. if _, ok := knownByType[eventType]; ok { return putr.save(eventType, event) } // If someone is already creating the event collection for this new type, // then append this event to the queue for later save. if _, ok := eventsToSaveByType[eventType]; ok { eventsToSaveByType[eventType] = append(eventsToSaveByType[eventType], event) } // Otherwise, it's up to us to see if the collection exists, verify the // associated indexes, create the corresponding metrics collection, and save // any events that have queued up in the interim! // First add the new event to the queue. eventsToSaveByType[eventType] = append(eventsToSaveByType[eventType], event) // If the events collection exists, then we assume the metrics & indexes do // too. Otherwise, we must create the required collections and indexes. Note // that if you want to customize the size of the capped metrics collection, // or add custom indexes, you can still do all that by hand. // Save any pending events to the new collection. saveEvents := func() { knownByType[eventType] = true for _, eventToSave := range eventsToSaveByType[eventType] { putr.save(eventType, eventToSave) } delete(eventsToSaveByType, event.Type) } names, _ := putr.db.CollectionNames() for _, name := range names { if name == eventType+"_events" { saveEvents() return nil } } events := putr.db.C(eventType + "_events") // Events are indexed by time. events.EnsureIndex(mgo.Index{Key: []string{"t"}}) // Create a capped collection for metrics. Three indexes are required: one // for finding metrics, one (_id) for updating, and one for invalidation. metrics := putr.db.C(eventType + "_metrics") err := metrics.Create(&mgo.CollectionInfo{Capped: true, MaxBytes: 1e7, ForceIdIndex: true}) if err != nil { return err } metrics.EnsureIndex(mgo.Index{Key: []string{"i", "_id.e", "_id.l", "_id.t"}}) metrics.EnsureIndex(mgo.Index{Key: []string{"i", "_id.l", "_id.t"}}) saveEvents() return nil }
//newPetition creates a petition from an http.Request. It checks header fields and make necessary transformations. //The body is read and saved as a slice of byte. func newPetition(original *http.Request) (*Petition, error) { targetHost := original.Header.Get(RelayerHost) if targetHost == "" { return nil, fmt.Errorf("gridas: Missing mandatory header %s", RelayerHost) } original.Header.Del(RelayerHost) scheme := strings.ToLower(original.Header.Get(RelayerProtocol)) switch scheme { case "http", "https": case "": scheme = "http" default: mylog.Debug("unsupported protocol", scheme) return nil, fmt.Errorf("gridas: unsupported protocol %s", scheme) } original.Header.Del(RelayerProtocol) traceID := original.Header.Get(RelayerTraceID) if traceID == "" { //Just in case an older version client using "Topic" traceID = original.Header.Get(RelayerTopic) } original.Header.Del(RelayerTraceID) original.Header.Del(RelayerTopic) //Delete older header fields, ignore them, do nothing yet original.Header.Del(RelayerProxy) original.Header.Del(RelayerRetry) { //Hack for clients of older version const HTTPS = "https://" const HTTPSLen = len(HTTPS) const HTTP = "http://" const HTTPLen = len(HTTP) if strings.HasPrefix(targetHost, HTTPS) { targetHost = targetHost[HTTPSLen:] scheme = "https" } else if strings.HasPrefix(targetHost, HTTP) { targetHost = targetHost[HTTPLen:] scheme = "http" } } //save body content body, err := ioutil.ReadAll(original.Body) if err != nil { mylog.Debugf("error reading body request %v %+v", err, original) return nil, err } id := uuid.New() relayedRequest := &Petition{ ID: id, Body: body, Method: original.Method, URL: original.URL, Proto: original.Proto, // "HTTP/1.0" Header: original.Header, Trailer: original.Trailer, RemoteAddr: original.RemoteAddr, RequestURI: original.RequestURI, TargetHost: targetHost, TargetScheme: scheme, Created: bson.Now(), TraceID: traceID} return relayedRequest, nil }
func (s *StoreSuite) TestLogCharmEvent(c *C) { url1 := charm.MustParseURL("cs:oneiric/wordpress") url2 := charm.MustParseURL("cs:oneiric/mysql") urls := []*charm.URL{url1, url2} event1 := &store.CharmEvent{ Kind: store.EventPublished, Revision: 42, Digest: "revKey1", URLs: urls, Warnings: []string{"A warning."}, Time: time.Unix(1, 0), } event2 := &store.CharmEvent{ Kind: store.EventPublished, Revision: 42, Digest: "revKey2", URLs: urls, Time: time.Unix(1, 0), } event3 := &store.CharmEvent{ Kind: store.EventPublishError, Digest: "revKey2", Errors: []string{"An error."}, URLs: urls[:1], } for _, event := range []*store.CharmEvent{event1, event2, event3} { err := s.store.LogCharmEvent(event) c.Assert(err, IsNil) } events := s.Session.DB("juju").C("events") var s1, s2 map[string]interface{} err := events.Find(bson.M{"digest": "revKey1"}).One(&s1) c.Assert(err, IsNil) c.Assert(s1["kind"], Equals, int(store.EventPublished)) c.Assert(s1["urls"], DeepEquals, []interface{}{"cs:oneiric/wordpress", "cs:oneiric/mysql"}) c.Assert(s1["warnings"], DeepEquals, []interface{}{"A warning."}) c.Assert(s1["errors"], IsNil) c.Assert(s1["time"], DeepEquals, time.Unix(1, 0)) err = events.Find(bson.M{"digest": "revKey2", "kind": store.EventPublishError}).One(&s2) c.Assert(err, IsNil) c.Assert(s2["urls"], DeepEquals, []interface{}{"cs:oneiric/wordpress"}) c.Assert(s2["warnings"], IsNil) c.Assert(s2["errors"], DeepEquals, []interface{}{"An error."}) c.Assert(s2["time"].(time.Time).After(bson.Now().Add(-10e9)), Equals, true) // Mongo stores timestamps in milliseconds, so chop // off the extra bits for comparison. event3.Time = time.Unix(0, event3.Time.UnixNano()/1e6*1e6) event, err := s.store.CharmEvent(urls[0], "revKey2") c.Assert(err, IsNil) c.Assert(event, DeepEquals, event3) event, err = s.store.CharmEvent(urls[1], "revKey1") c.Assert(err, IsNil) c.Assert(event, DeepEquals, event1) event, err = s.store.CharmEvent(urls[1], "revKeyX") c.Assert(err, Equals, store.ErrNotFound) c.Assert(event, IsNil) }