github.com/omniscale/go-osm@v0.3.1/parser/pbf/parser_test.go (about)

     1  package pbf
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"reflect"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/omniscale/go-osm"
    12  )
    13  
    14  func TestParser(t *testing.T) {
    15  	checkParser(t, false)
    16  }
    17  
    18  func BenchmarkParser(b *testing.B) {
    19  	b.ReportAllocs()
    20  	for i := 0; i < b.N; i++ {
    21  		checkParser(b, false)
    22  	}
    23  }
    24  
    25  func BenchmarkParser_IncludeMetadata(b *testing.B) {
    26  	b.ReportAllocs()
    27  	for i := 0; i < b.N; i++ {
    28  		checkParser(b, true)
    29  	}
    30  }
    31  
    32  func checkParser(t testing.TB, includeMD bool) {
    33  	conf := Config{
    34  		Coords:          make(chan []osm.Node),
    35  		Nodes:           make(chan []osm.Node),
    36  		Ways:            make(chan []osm.Way),
    37  		Relations:       make(chan []osm.Relation),
    38  		IncludeMetadata: includeMD,
    39  	}
    40  
    41  	f, err := os.Open("./monaco-20150428.osm.pbf")
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	defer f.Close()
    46  
    47  	p := New(f, conf)
    48  
    49  	wg := sync.WaitGroup{}
    50  
    51  	var numNodes, numCoords, numWays, numRelations int64
    52  
    53  	go func() {
    54  		wg.Add(1)
    55  		for nd := range conf.Nodes {
    56  			numNodes += int64(len(nd))
    57  		}
    58  		wg.Done()
    59  	}()
    60  
    61  	go func() {
    62  		wg.Add(1)
    63  		for nd := range conf.Coords {
    64  			numCoords += int64(len(nd))
    65  		}
    66  		wg.Done()
    67  	}()
    68  
    69  	go func() {
    70  		wg.Add(1)
    71  		for ways := range conf.Ways {
    72  			numWays += int64(len(ways))
    73  		}
    74  		wg.Done()
    75  	}()
    76  
    77  	go func() {
    78  		wg.Add(1)
    79  		for rels := range conf.Relations {
    80  			numRelations += int64(len(rels))
    81  		}
    82  		wg.Done()
    83  	}()
    84  
    85  	err = p.Parse(context.Background())
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  	wg.Wait()
    90  
    91  	if numCoords != 17233 {
    92  		t.Error("parsed an unexpected number of coords:", numCoords)
    93  	}
    94  	if numNodes != 978 {
    95  		t.Error("parsed an unexpected number of nodes:", numNodes)
    96  	}
    97  	if numWays != 2398 {
    98  		t.Error("parsed an unexpected number of ways:", numWays)
    99  	}
   100  	if numRelations != 108 {
   101  		t.Error("parsed an unexpected number of relations:", numRelations)
   102  	}
   103  }
   104  
   105  func TestParseCoords(t *testing.T) {
   106  	conf := Config{
   107  		Coords: make(chan []osm.Node),
   108  	}
   109  
   110  	f, err := os.Open("./monaco-20150428.osm.pbf")
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	defer f.Close()
   115  
   116  	p := New(f, conf)
   117  
   118  	wg := sync.WaitGroup{}
   119  
   120  	var numCoords int64
   121  
   122  	go func() {
   123  		wg.Add(1)
   124  		for nd := range conf.Coords {
   125  			numCoords += int64(len(nd))
   126  		}
   127  		wg.Done()
   128  	}()
   129  
   130  	err = p.Parse(context.Background())
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	wg.Wait()
   135  
   136  	if numCoords != 17233 {
   137  		t.Error("parsed an unexpected number of coords:", numCoords)
   138  	}
   139  }
   140  
   141  func TestParseNodes(t *testing.T) {
   142  	conf := Config{
   143  		Nodes: make(chan []osm.Node),
   144  	}
   145  
   146  	f, err := os.Open("./monaco-20150428.osm.pbf")
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	defer f.Close()
   151  
   152  	p := New(f, conf)
   153  
   154  	wg := sync.WaitGroup{}
   155  
   156  	var numNodes int64
   157  
   158  	go func() {
   159  		wg.Add(1)
   160  		for nd := range conf.Nodes {
   161  			numNodes += int64(len(nd))
   162  		}
   163  		wg.Done()
   164  	}()
   165  
   166  	err = p.Parse(context.Background())
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	wg.Wait()
   171  
   172  	if numNodes != 17233 {
   173  		t.Error("parsed an unexpected number of nodes:", numNodes)
   174  	}
   175  }
   176  
   177  func TestParserNotify(t *testing.T) {
   178  	conf := Config{
   179  		Coords:    make(chan []osm.Node),
   180  		Nodes:     make(chan []osm.Node),
   181  		Ways:      make(chan []osm.Way),
   182  		Relations: make(chan []osm.Relation),
   183  	}
   184  
   185  	f, err := os.Open("./monaco-20150428.osm.pbf")
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  	defer f.Close()
   190  
   191  	nodesWg := sync.WaitGroup{} // use nodesWg to wait till all nodes are processed
   192  	nodesProcessed := false
   193  	conf.OnFirstWay = func() {
   194  		// Send nil sentinal to nodes/coords goroutines to indicate that they
   195  		// should call nodesWg.Done after processing.
   196  		// Note: Need to send as many nils as there are goroutines.
   197  		conf.Coords <- nil
   198  		conf.Nodes <- nil
   199  		nodesProcessed = true
   200  		nodesWg.Wait()
   201  	}
   202  
   203  	waysWg := sync.WaitGroup{} // use waysWg to wait till all ways are processed
   204  	waysProcessed := false
   205  	conf.OnFirstRelation = func() {
   206  		// Send nil sentinal to ways goroutines to indicate that they
   207  		// should call waysWg.Done after processing.
   208  		// Note: Need to send as many nils as there are goroutines.
   209  		conf.Ways <- nil
   210  		waysProcessed = true
   211  		waysWg.Wait()
   212  	}
   213  
   214  	p := New(f, conf)
   215  
   216  	wg := sync.WaitGroup{}
   217  
   218  	var numNodes, numCoords, numWays, numRelations int64
   219  
   220  	nodesWg.Add(1)
   221  	go func() {
   222  		wg.Add(1)
   223  		for nd := range conf.Nodes {
   224  			if nd == nil {
   225  				nodesWg.Done()
   226  				nodesWg.Wait()
   227  				continue
   228  			}
   229  			numNodes += int64(len(nd))
   230  		}
   231  		wg.Done()
   232  	}()
   233  
   234  	nodesWg.Add(1)
   235  	go func() {
   236  		wg.Add(1)
   237  		for nd := range conf.Coords {
   238  			if nd == nil {
   239  				nodesWg.Done()
   240  				nodesWg.Wait()
   241  				continue
   242  			}
   243  			numCoords += int64(len(nd))
   244  		}
   245  		wg.Done()
   246  	}()
   247  
   248  	waysWg.Add(1)
   249  	go func() {
   250  		wg.Add(1)
   251  		for ways := range conf.Ways {
   252  			if ways == nil {
   253  				waysWg.Done()
   254  				waysWg.Wait()
   255  				continue
   256  			}
   257  			if !nodesProcessed {
   258  				t.Fatal("received ways before all nodes were processed")
   259  			}
   260  			numWays += int64(len(ways))
   261  		}
   262  		wg.Done()
   263  	}()
   264  
   265  	go func() {
   266  		wg.Add(1)
   267  		for rels := range conf.Relations {
   268  			if !nodesProcessed {
   269  				t.Fatal("received relations before all nodes were processed")
   270  			}
   271  			if !waysProcessed {
   272  				t.Fatal("received relations before all ways were processed")
   273  			}
   274  			numRelations += int64(len(rels))
   275  		}
   276  		wg.Done()
   277  	}()
   278  
   279  	err = p.Parse(context.Background())
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	wg.Wait()
   284  
   285  	if numCoords != 17233 {
   286  		t.Error("parsed an unexpected number of coords:", numCoords)
   287  	}
   288  	if numNodes != 978 {
   289  		t.Error("parsed an unexpected number of nodes:", numNodes)
   290  	}
   291  	if numWays != 2398 {
   292  		t.Error("parsed an unexpected number of ways:", numWays)
   293  	}
   294  	if numRelations != 108 {
   295  		t.Error("parsed an unexpected number of relations:", numRelations)
   296  	}
   297  }
   298  
   299  func TestParseCancel(t *testing.T) {
   300  	conf := Config{
   301  		Nodes:       make(chan []osm.Node),
   302  		Ways:        make(chan []osm.Way),
   303  		Relations:   make(chan []osm.Relation),
   304  		Concurrency: 1,
   305  	}
   306  
   307  	f, err := os.Open("./monaco-20150428.osm.pbf")
   308  	if err != nil {
   309  		t.Fatal(err)
   310  	}
   311  	defer f.Close()
   312  
   313  	p := New(f, conf)
   314  
   315  	wg := sync.WaitGroup{}
   316  	ctx, stop := context.WithCancel(context.Background())
   317  	var numNodes, numWays, numRelations int64
   318  
   319  	go func() {
   320  		wg.Add(1)
   321  		for nd := range conf.Nodes {
   322  			numNodes += int64(len(nd))
   323  			// stop after first parsed nodes
   324  			stop()
   325  		}
   326  		wg.Done()
   327  	}()
   328  	go func() {
   329  		wg.Add(1)
   330  		for ways := range conf.Ways {
   331  			numWays += int64(len(ways))
   332  		}
   333  		wg.Done()
   334  	}()
   335  	go func() {
   336  		wg.Add(1)
   337  		for rels := range conf.Relations {
   338  			numRelations += int64(len(rels))
   339  		}
   340  		wg.Done()
   341  	}()
   342  
   343  	err = p.Parse(ctx)
   344  	if err != context.Canceled {
   345  		t.Fatal(err)
   346  	}
   347  	wg.Wait()
   348  
   349  	// only two blocks of 8k nodes should be parsed before everything is stop()ed
   350  	if numNodes != 16000 {
   351  		t.Error("parsed an unexpected number of nodes:", numNodes)
   352  	}
   353  	if numWays != 0 {
   354  		t.Error("parsed an unexpected number of ways:", numWays)
   355  	}
   356  	if numRelations != 0 {
   357  		t.Error("parsed an unexpected number of relations:", numRelations)
   358  	}
   359  }
   360  
   361  func TestParseMetadata(t *testing.T) {
   362  	conf := Config{
   363  		IncludeMetadata: true,
   364  		Nodes:           make(chan []osm.Node),
   365  		Ways:            make(chan []osm.Way),
   366  		Relations:       make(chan []osm.Relation),
   367  		Concurrency:     1,
   368  	}
   369  
   370  	f, err := os.Open("./monaco-20150428.osm.pbf")
   371  	if err != nil {
   372  		t.Fatal(err)
   373  	}
   374  	defer f.Close()
   375  
   376  	p := New(f, conf)
   377  
   378  	wg := sync.WaitGroup{}
   379  
   380  	var nodes []osm.Node
   381  	wg.Add(1)
   382  	go func() {
   383  		for nds := range conf.Nodes {
   384  			nodes = append(nodes, nds...)
   385  		}
   386  		wg.Done()
   387  	}()
   388  
   389  	var ways []osm.Way
   390  	wg.Add(1)
   391  	go func() {
   392  		for ws := range conf.Ways {
   393  			ways = append(ways, ws...)
   394  		}
   395  		wg.Done()
   396  	}()
   397  
   398  	var rels []osm.Relation
   399  	wg.Add(1)
   400  	go func() {
   401  		for rs := range conf.Relations {
   402  			rels = append(rels, rs...)
   403  		}
   404  		wg.Done()
   405  	}()
   406  
   407  	err = p.Parse(context.Background())
   408  	if err != nil {
   409  		t.Fatal(err)
   410  	}
   411  	wg.Wait()
   412  
   413  	for _, tc := range []struct {
   414  		Idx  int
   415  		Want osm.Node
   416  	}{
   417  		{Idx: 0,
   418  			Want: osm.Node{
   419  				Element: osm.Element{
   420  					ID: 21911863,
   421  					Metadata: &osm.Metadata{
   422  						UserID:    378737,
   423  						UserName:  "Scrup",
   424  						Version:   5,
   425  						Timestamp: time.Unix(1335970231, 0),
   426  						Changeset: 11480240,
   427  					},
   428  				},
   429  				Lat:  43.737012500000006,
   430  				Long: 7.422028,
   431  			},
   432  		},
   433  		{Idx: 2,
   434  			Want: osm.Node{
   435  				Element: osm.Element{
   436  					ID:   21911886,
   437  					Tags: osm.Tags{"crossing_ref": "zebra", "highway": "crossing"},
   438  					Metadata: &osm.Metadata{
   439  						UserID:    378737,
   440  						UserName:  "Scrup",
   441  						Version:   8,
   442  						Timestamp: time.Unix(1335884779, 0),
   443  						Changeset: 11470653,
   444  					},
   445  				},
   446  				Lat:  43.737239900000006,
   447  				Long: 7.423498500000001,
   448  			},
   449  		},
   450  	} {
   451  		if !reflect.DeepEqual(nodes[tc.Idx], tc.Want) {
   452  			t.Errorf("unexpected node, got:\n%#v\n%#v\nwant:\n%#v\n%#v", nodes[tc.Idx], nodes[tc.Idx].Metadata, tc.Want, tc.Want.Metadata)
   453  		}
   454  	}
   455  
   456  	for _, tc := range []struct {
   457  		Idx  int
   458  		Want osm.Way
   459  	}{
   460  		{Idx: 0,
   461  			Want: osm.Way{
   462  				Element: osm.Element{
   463  					ID:   4097656,
   464  					Tags: osm.Tags{"highway": "primary", "name": "Avenue Princesse Alice", "oneway": "yes"},
   465  					Metadata: &osm.Metadata{
   466  						UserID:    852996,
   467  						UserName:  "Mg2",
   468  						Version:   7,
   469  						Timestamp: time.Unix(1417551724, 0),
   470  						Changeset: 27187519,
   471  					},
   472  				},
   473  				Refs: []int64{21912089, 1079750744, 2104793864, 1110560507, 21912093, 21912095, 1079751630, 21912097, 21912099},
   474  			},
   475  		},
   476  		{Idx: 2,
   477  			Want: osm.Way{
   478  				Element: osm.Element{
   479  					ID:   4224972,
   480  					Tags: osm.Tags{"name": "Avenue des Papalins", "oneway": "yes", "highway": "residential"},
   481  					Metadata: &osm.Metadata{
   482  						UserID:    393883,
   483  						UserName:  "fmalamaire",
   484  						Version:   9,
   485  						Timestamp: time.Unix(1368522546, 0),
   486  						Changeset: 16122419,
   487  					},
   488  				},
   489  				Refs: []int64{25177418, 25177397},
   490  			},
   491  		},
   492  	} {
   493  		if !reflect.DeepEqual(ways[tc.Idx], tc.Want) {
   494  			t.Errorf("unexpected way, got:\n%#v\n%#v\nwant:\n%#v\n%#v", ways[tc.Idx], ways[tc.Idx].Metadata, tc.Want, tc.Want.Metadata)
   495  		}
   496  	}
   497  
   498  	for _, tc := range []struct {
   499  		Idx  int
   500  		Want osm.Relation
   501  	}{
   502  		{Idx: 26,
   503  			Want: osm.Relation{
   504  				Element: osm.Element{
   505  					ID:   1369631,
   506  					Tags: osm.Tags{"type": "multipolygon"},
   507  					Metadata: &osm.Metadata{
   508  						UserID:    110263,
   509  						UserName:  "werner2101",
   510  						Version:   2,
   511  						Timestamp: time.Unix(1298228849, 0),
   512  						Changeset: 7346501,
   513  					},
   514  				},
   515  				Members: []osm.Member{
   516  					osm.Member{ID: 94452671, Type: 1, Role: "inner"},
   517  					osm.Member{ID: 94452619, Type: 1, Role: "outer"},
   518  				},
   519  			},
   520  		},
   521  	} {
   522  		if !reflect.DeepEqual(rels[tc.Idx], tc.Want) {
   523  			t.Errorf("unexpected rel, got:\n%#v\n%#v\nwant:\n%#v\n%#v", rels[tc.Idx], rels[tc.Idx].Metadata, tc.Want, tc.Want.Metadata)
   524  		}
   525  	}
   526  }